build-baremetal 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. #!/usr/bin/env python3
  2. import os
  3. import common
  4. from shell_helpers import LF
  5. class Main(common.BuildCliFunction):
  6. def __init__(self):
  7. super().__init__(
  8. defaults={
  9. 'gcc_which':'crosstool-ng',
  10. },
  11. description='''\
  12. Build the baremetal examples with crosstool-NG.
  13. ''',
  14. supported_archs=common.consts['crosstool_ng_supported_archs']
  15. )
  16. self._add_argument('--ccflags')
  17. self._add_argument('--force-rebuild')
  18. self._add_argument('--optimization-level')
  19. def build(self):
  20. build_dir = self.get_build_dir()
  21. bootloader_obj = os.path.join(
  22. self.env['baremetal_build_lib_dir'],
  23. 'bootloader{}'.format(self.env['obj_ext'])
  24. )
  25. common_obj = os.path.join(
  26. self.env['baremetal_build_lib_dir'],
  27. self.env['common_basename_noext'] + self.env['obj_ext']
  28. )
  29. syscalls_basename_noext = 'syscalls'
  30. syscalls_src = os.path.join(
  31. self.env['baremetal_source_lib_dir'],
  32. syscalls_basename_noext + self.env['c_ext']
  33. )
  34. syscalls_obj = os.path.join(
  35. self.env['baremetal_build_lib_dir'],
  36. syscalls_basename_noext + self.env['obj_ext']
  37. )
  38. common_objs = [common_obj, syscalls_obj]
  39. cflags = [
  40. '-I', self.env['baremetal_source_lib_dir'], LF,
  41. '-I', self.env['root_dir'], LF,
  42. '-O{}'.format(self.env['optimization_level']), LF,
  43. '-ggdb3', LF,
  44. '-mcpu={}'.format(self.env['mcpu']), LF,
  45. '-nostartfiles', LF,
  46. ]
  47. if self.env['arch'] == 'arm':
  48. cflags.extend([
  49. '-mhard-float', LF,
  50. # This uses the soft float ABI for calling functions from objets in Newlib which
  51. # our crosstool-NG config compiles with soft floats, while emiting hard float
  52. # from C and allowing us to use it from assembly, e.g. for the VMRS instruction:
  53. # which would otherwise fail "with selected processor does not support XXX in ARM mode"
  54. # Bibliography:
  55. # - https://stackoverflow.com/questions/9753749/arm-compilation-error-vfp-registered-used-by-executable-not-object-file
  56. # - https://stackoverflow.com/questions/41131432/cross-compiling-error-selected-processor-does-not-support-fmrx-r3-fpexc-in/41131782#41131782
  57. # - https://embeddedartistry.com/blog/2017/10/9/r1q7pksku2q3gww9rpqef0dnskphtc
  58. '-mfloat-abi=softfp', LF,
  59. '-mfpu=crypto-neon-fp-armv8', LF,
  60. ])
  61. cflags_after = ['-lm']
  62. if self.env['emulator'] == 'gem5':
  63. if self.env['machine'] == 'VExpress_GEM5_V1':
  64. entry_address = 0x80000000
  65. uart_address = 0x1c090000
  66. elif self.env['machine'] == 'RealViewPBX':
  67. entry_address = 0x10000
  68. uart_address = 0x10009000
  69. else:
  70. raise Exception('unknown machine: ' + self.env['machine'])
  71. cflags.extend([
  72. '-D', 'GEM5'.format(uart_address), LF,
  73. '-DLKMC_M5OPS_ENABLE=1', LF,
  74. ])
  75. else:
  76. entry_address = 0x40000000
  77. uart_address = 0x09000000
  78. os.makedirs(build_dir, exist_ok=True)
  79. os.makedirs(self.env['baremetal_build_lib_dir'], exist_ok=True)
  80. src = os.path.join(
  81. self.env['baremetal_source_lib_dir'],
  82. '{}{}'.format(
  83. self.env['arch'],
  84. self.env['asm_ext']
  85. )
  86. )
  87. cflags.extend(self.sh.shlex_split(self.env['ccflags']))
  88. if self.need_rebuild([src], bootloader_obj):
  89. self.sh.run_cmd(
  90. [self.env['gcc_path'], LF] +
  91. cflags +
  92. [
  93. '-c', LF,
  94. '-o', bootloader_obj, LF,
  95. src, LF,
  96. ] +
  97. cflags_after
  98. )
  99. for src, obj in [
  100. (self.env['common_c'], common_obj),
  101. (syscalls_src, syscalls_obj),
  102. ]:
  103. if self.need_rebuild([src, self.env['common_h']], obj):
  104. self.sh.run_cmd(
  105. [self.env['gcc_path'], LF] +
  106. cflags +
  107. [
  108. '-D', 'UART0_ADDR={:#x}'.format(uart_address), LF,
  109. '-c', LF,
  110. '-o', obj, LF,
  111. src, LF,
  112. ] +
  113. cflags_after
  114. )
  115. for subpath in [
  116. '',
  117. 'interactive',
  118. self.env['baremetal_source_arch_subpath'],
  119. os.path.join(self.env['baremetal_source_arch_subpath'], 'no_bootloader'),
  120. ]:
  121. in_dir = os.path.join(self.env['baremetal_source_dir'], subpath)
  122. if os.path.isdir(in_dir):
  123. out_dir = os.path.join(self.env['baremetal_build_dir'], subpath)
  124. os.makedirs(out_dir, exist_ok=True)
  125. common_objs_bootloader = common_objs.copy()
  126. if os.path.basename(subpath) != 'no_bootloader':
  127. common_objs_bootloader.append(bootloader_obj)
  128. for in_basename in sorted(os.listdir(in_dir)):
  129. in_path = os.path.join(in_dir, in_basename)
  130. in_name, in_ext = os.path.splitext(in_basename)
  131. if (
  132. os.path.isfile(in_path) and
  133. in_ext in self.env['build_in_exts']
  134. ):
  135. out = os.path.join(out_dir, in_name + self.env['baremetal_build_ext'])
  136. src = os.path.join(self.env['baremetal_source_dir'], in_path)
  137. if self.need_rebuild(
  138. common_objs_bootloader +
  139. [
  140. src,
  141. self.env['baremetal_link_script'],
  142. self.env['common_h']
  143. ],
  144. out
  145. ):
  146. self.sh.run_cmd(
  147. [self.env['gcc_path'], LF] +
  148. cflags +
  149. [
  150. '-Wl,--section-start=.text={:#x}'.format(entry_address), LF,
  151. '-o', out, LF,
  152. '-T', self.env['baremetal_link_script'], LF,
  153. ] +
  154. [
  155. src, LF,
  156. ] +
  157. self.sh.add_newlines(common_objs_bootloader) +
  158. cflags_after
  159. )
  160. def get_build_dir(self):
  161. return self.env['baremetal_build_dir']
  162. if __name__ == '__main__':
  163. Main().cli()