@@ -237,6 +237,227 @@ def _build_binary(ctx, exec_env, name, deps, kind):
237237 )
238238 return provides , signed
239239
240+ def _opentitan_binary_blob (ctx ):
241+ """
242+ Create a library containing the library as a binary blob and a parser to
243+ this binary blob. The following steps are done to create the final library:
244+ - Generate jump table and its parser from public header files and a linker
245+ script for the creation of the binary blob
246+ - Compile the jump table with the library and create an executable
247+ from it using the linker script
248+ - Extract the binary from the executable (the last bytes can contain the hash
249+ - Compute the hash of the binary file and replace its last bytes by the hash
250+ - Create a c file that contain the binary blob as an array
251+ - Compile the parser and the binary blob array
252+ - Create the library
253+ """
254+
255+ # Name for the files generated by this rule
256+ name_jump_table_c = ctx .attr .name + "_jump_table.c"
257+ name_jump_table_h = ctx .attr .name + "_jump_table.h"
258+ name_lib_parser = ctx .attr .name + "_lib_parser.c"
259+ name_linker_script = ctx .attr .name + "_linker_script.ld"
260+ name_elf = ctx .attr .name + ".elf"
261+ name_bin = ctx .attr .name + ".bin"
262+ name_sha = ctx .attr .name + ".sha384"
263+ name_bin_sha = ctx .attr .name + "_sha384.bin"
264+ name_blob = ctx .attr .name + "_blob.c"
265+ name_library = ctx .attr .name + ".a"
266+
267+ deps_blob = ctx .attr .deps_blob
268+ deps_lib = ctx .attr .deps
269+
270+ cc_toolchain = find_cc_toolchain (ctx )
271+
272+ # Declare output files generated by generate_jump_table.py.
273+ linker_script = ctx .actions .declare_file (name_linker_script )
274+ jump_table_c = ctx .actions .declare_file (name_jump_table_c )
275+ jump_table_h = ctx .actions .declare_file (name_jump_table_h )
276+ lib_parser_c = ctx .actions .declare_file (name_lib_parser )
277+
278+ # Prepare the arguments for generate_jump_table.py
279+ extra_args = []
280+ if ctx .attr .pic :
281+ extra_args .append ("--pic" )
282+
283+ if len (ctx .files .config ) == 1 :
284+ extra_args .append ("--config={}" .format (ctx .files .config [0 ].path ))
285+
286+ header = ctx .attr .header
287+ header_list = [h for head in ctx .attr .header for h in head .files .to_list ()]
288+ address = ctx .var .get ("ADDRESS" , "0" )
289+
290+ # Generate jump table and parser files from public headers
291+ ctx .actions .run (
292+ outputs = [linker_script , jump_table_c , jump_table_h , lib_parser_c ],
293+ inputs = header_list + ctx .files .config ,
294+ arguments = [
295+ "--binary_blob" ,
296+ "--address={}" .format (address ),
297+ "--out-dir={}" .format (jump_table_c .dirname ),
298+ "--prefix={}" .format (ctx .attr .name ),
299+ ] + extra_args + [h .path for h in header_list ],
300+ executable = ctx .executable ._generate_jump_table ,
301+ )
302+
303+ features = cc_common .configure_features (
304+ ctx = ctx ,
305+ cc_toolchain = cc_toolchain ,
306+ requested_features = ctx .features ,
307+ unsupported_features = ctx .disabled_features ,
308+ )
309+
310+ compilation_contexts = [
311+ dep_blob [CcInfo ].compilation_context
312+ for dep_blob in deps_blob
313+ ]
314+
315+ # Compile the jump table and include it to libotcrypto library
316+ hdrs = [jump_table_h ]
317+ srcs = [jump_table_c ]
318+ cctx , cout = cc_common .compile (
319+ name = ctx .attr .name ,
320+ actions = ctx .actions ,
321+ feature_configuration = features ,
322+ cc_toolchain = cc_toolchain ,
323+ compilation_contexts = compilation_contexts ,
324+ srcs = srcs ,
325+ private_hdrs = hdrs ,
326+ user_compile_flags = ["-ffreestanding" ] + _expand (ctx , "copts" , ctx .attr .copts ),
327+ defines = _expand (ctx , "defines" , ctx .attr .defines ),
328+ local_defines = _expand (ctx , "local_defines" , ctx .attr .local_defines ),
329+ quote_includes = _expand (ctx , "includes" , ctx .attr .includes ),
330+ )
331+
332+ linking_contexts = [
333+ dep_blob [CcInfo ].linking_context
334+ for dep_blob in deps_blob
335+ ]
336+
337+ # Add the linker script to the linking_contexts
338+ linking_input = cc_common .create_linker_input (owner = ctx .label , additional_inputs = depset ([linker_script ]))
339+ linking_contexts .append (cc_common .create_linking_context (linker_inputs = depset ([linking_input ])))
340+ extra_linkopts = (ctx .attr .linkopts or [])
341+
342+ linkopts = [
343+ "-static" ,
344+ "-nostdlib" ,
345+ "-nostartfiles" ,
346+ "-Wl,-T{}" .format (linker_script .path ),
347+ ] + _expand (ctx , "linkopts" , extra_linkopts )
348+
349+ # Create an executable from the libotcrypto by using the linker script
350+ elf_file = ctx .actions .declare_file (name_elf )
351+ linking_outputs = cc_common .link (
352+ name = name_elf ,
353+ actions = ctx .actions ,
354+ output_type = "executable" ,
355+ feature_configuration = features ,
356+ cc_toolchain = cc_toolchain ,
357+ compilation_outputs = cout ,
358+ linking_contexts = linking_contexts ,
359+ user_link_flags = linkopts ,
360+ )
361+
362+ # Create a disassembly file from the elf file
363+ dis_file = obj_disassemble (
364+ ctx ,
365+ name = ctx .attr .name ,
366+ src = linking_outputs .executable ,
367+ )
368+
369+ # Extract the binary from the elf file
370+ binary_file = ctx .actions .declare_file (name_bin )
371+ ctx .actions .run (
372+ outputs = [binary_file ],
373+ inputs = [elf_file ],
374+ executable = ctx .executable ._riscv32_objcopy ,
375+ arguments = ["-O" , "binary" , elf_file .path , binary_file .path ],
376+ use_default_shell_env = True ,
377+ )
378+
379+ # Compute the hash of the binary file
380+ hash_file = ctx .actions .declare_file (name_sha )
381+ ctx .actions .run_shell (
382+ inputs = [binary_file ],
383+ outputs = [hash_file ],
384+ # Remove the last 48 bytes (the hash table) before computing the hash
385+ command = "head -c -48 {} | sha384sum | awk '{{print $1}}' | xxd -r -p > {}" .format (binary_file .path , hash_file .path ),
386+ )
387+
388+ # Compute the hash of the binary file
389+ binary_hash_file = ctx .actions .declare_file (name_bin_sha )
390+ ctx .actions .run_shell (
391+ inputs = [binary_file , hash_file ],
392+ outputs = [binary_hash_file ],
393+ # Replace the last 48 bytes by the hash
394+ command = "head -c -48 {} > {} && cat {} >> {}" .format (binary_file .path , binary_hash_file .path , hash_file .path , binary_hash_file .path ),
395+ )
396+
397+ # Generate a C file that contain an array (blob) of the binary file content
398+ blob_file = ctx .actions .declare_file (name_blob )
399+ ctx .actions .run_shell (
400+ inputs = [binary_hash_file ],
401+ outputs = [blob_file ],
402+ command = "xxd -i -n blob {} | sed 's/unsigned char/const unsigned char __attribute__((section (\" .text.blob\" ), aligned(4)))/' > {}"
403+ .format (binary_hash_file .path , blob_file .path ),
404+ )
405+
406+ # Creation of the library that contains the binary blob and lib_parser.c
407+ # to be able to parse it
408+ srcs_lib = [blob_file , lib_parser_c ]
409+ hdrs_lib = ctx .files .hdrs + [jump_table_h ] + header_list
410+ compilation_contexts = [
411+ dep_lib [CcInfo ].compilation_context
412+ for dep_lib in deps_lib
413+ ]
414+
415+ (ctx_object , objects ) = cc_common .compile (
416+ name = ctx .attr .name ,
417+ actions = ctx .actions ,
418+ feature_configuration = features ,
419+ cc_toolchain = cc_toolchain ,
420+ compilation_contexts = compilation_contexts ,
421+ srcs = srcs_lib ,
422+ private_hdrs = hdrs_lib ,
423+ user_compile_flags = _expand (ctx , "copts" , ctx .attr .copts ),
424+ defines = _expand (ctx , "defines" , ctx .attr .defines ),
425+ local_defines = _expand (ctx , "local_defines" , ctx .attr .local_defines ),
426+ quote_includes = _expand (ctx , "includes" , ctx .attr .includes ),
427+ )
428+
429+ # Create a library from it
430+ object_files = objects .objects
431+ library_file = ctx .actions .declare_file (name_library )
432+ ctx .actions .run (
433+ inputs = object_files ,
434+ outputs = [library_file ],
435+ executable = ctx .executable ._riscv32_ar ,
436+ arguments = ["rcs" , library_file .path ] + [obj .path for obj in object_files ],
437+ )
438+
439+ return [
440+ DefaultInfo (files = depset ([library_file , dis_file , elf_file ])),
441+ OutputGroupInfo (
442+ elf_file = depset ([linking_outputs .executable ]),
443+ dis_file = depset ([dis_file ]),
444+ ),
445+ CcInfo (
446+ # The context allows consumers to link against this library
447+ linking_context = cc_common .create_linking_context (
448+ linker_inputs = depset ([cc_common .create_linker_input (
449+ owner = ctx .label ,
450+ libraries = depset ([cc_common .create_library_to_link (
451+ actions = ctx .actions ,
452+ feature_configuration = features ,
453+ cc_toolchain = cc_toolchain ,
454+ static_library = library_file ,
455+ )]),
456+ )]),
457+ ),
458+ ),
459+ ]
460+
240461def _opentitan_binary (ctx ):
241462 providers = []
242463 default_info = []
@@ -361,6 +582,53 @@ common_binary_attrs = {
361582 ),
362583}
363584
585+ opentitan_binary_blob = rv_rule (
586+ implementation = _opentitan_binary_blob ,
587+ attrs = dict (common_binary_attrs .items () + {
588+ "hdrs" : attr .label_list (
589+ allow_files = True ,
590+ doc = "The list of header file requires for the creation of the library." ,
591+ ),
592+ "header" : attr .label_list (
593+ allow_files = True ,
594+ doc = "Public header files to generate jump_table and parser." ,
595+ ),
596+ "config" : attr .label (
597+ default = None ,
598+ allow_files = True ,
599+ doc = "File containing the functions to be included into the blob" ,
600+ ),
601+ "deps_blob" : attr .label_list (
602+ providers = [CcInfo ],
603+ doc = "The list of other libraries to be for the creation of the binary blob." ,
604+ ),
605+ "pic" : attr .bool (
606+ default = False ,
607+ doc = "Indicate if the code is position independent " ,
608+ ),
609+ "_cc_toolchain" : attr .label (default = Label ("@bazel_tools//tools/cpp:current_cc_toolchain" )),
610+ "_riscv32_objcopy" : attr .label (
611+ default = Label ("@lowrisc_rv32imcb_toolchain//:bin/riscv32-unknown-elf-objcopy" ),
612+ allow_single_file = True ,
613+ executable = True ,
614+ cfg = "exec" ,
615+ ),
616+ "_riscv32_ar" : attr .label (
617+ default = Label ("@lowrisc_rv32imcb_toolchain//:bin/riscv32-unknown-elf-ar" ),
618+ allow_single_file = True ,
619+ executable = True ,
620+ cfg = "exec" ,
621+ ),
622+ "_generate_jump_table" : attr .label (
623+ default = "//util:generate_jump_table" ,
624+ executable = True ,
625+ cfg = "exec" ,
626+ ),
627+ }.items ()),
628+ fragments = ["cpp" ],
629+ toolchains = ["@rules_cc//cc:toolchain_type" ],
630+ )
631+
364632opentitan_binary = rv_rule (
365633 implementation = _opentitan_binary ,
366634 attrs = dict (common_binary_attrs .items () + {
0 commit comments