build_bootloader.py 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. # ZuluSCSI™ - Copyright (c) 2022 Rabbit Hole Computing™
  2. #
  3. # ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
  4. #
  5. # https://www.gnu.org/licenses/gpl-3.0.html
  6. # ----
  7. # This program is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation, either version 3 of the License, or
  10. # (at your option) any later version. 
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. # GNU General Public License for more details. 
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with this program.  If not, see <https://www.gnu.org/licenses/>.
  19. # Adds a platformio/Scons target to build the bootloader image.
  20. # It is basically a copy of the main firmware but using ZuluSCSI_bootloader.cpp
  21. # as the main() function.
  22. import os
  23. Import("env")
  24. # Build a version of ZuluSCSI_main.cpp that calls bootloader instead
  25. env2 = env.Clone()
  26. env2.Append(CPPFLAGS = "-DZULUSCSI_BOOTLOADER_MAIN")
  27. bootloader_main = env2.Object(
  28. os.path.join("$BUILD_DIR", "bootloader_main.o"),
  29. ["ZuluSCSI_main.cpp"]
  30. )
  31. # Include all other dependencies except ZuluSCSI_main.cpp
  32. dep_objs = []
  33. for nodelist in env["PIOBUILDFILES"]:
  34. for node in nodelist:
  35. filename = str(node.rfile())
  36. if 'ZuluSCSI_main' not in filename:
  37. dep_objs.append(node)
  38. # print("Bootloader dependencies: ", type(dep_objs), str([str(f.rfile()) for f in dep_objs]))
  39. # Use different linker script for bootloader
  40. if env2.GetProjectOption("ldscript_bootloader"):
  41. env2.Replace(LDSCRIPT_PATH = env2.GetProjectOption("ldscript_bootloader"))
  42. env2['LINKFLAGS'] = [a for a in env2['LINKFLAGS'] if not a.startswith('-T') and not a.endswith('.ld')]
  43. env2.Append(LINKFLAGS="-T" + env2.GetProjectOption("ldscript_bootloader"))
  44. # Build bootloader.elf
  45. bootloader_elf = env2.Program(
  46. os.path.join("$BUILD_DIR", "bootloader.elf"),
  47. [bootloader_main] + dep_objs
  48. )
  49. # Strip bootloader symbols so that it can be combined with main program
  50. bootloader_bin = env.ElfToBin(
  51. os.path.join("$BUILD_DIR", "bootloader.bin"),
  52. bootloader_elf
  53. )
  54. # Convert back to .o to facilitate linking
  55. def escape_cpp(path):
  56. '''Apply double-escaping for path name to include in generated C++ file'''
  57. result = ''
  58. for c in str(path).encode('utf-8'):
  59. if 32 <= c <= 127 and c not in (ord('\\'), ord('"')):
  60. result += chr(c)
  61. else:
  62. result += '\\\\%03o' % c
  63. return result
  64. temp_src = env.subst(os.path.join("$BUILD_DIR", "bootloader_bin.cpp"))
  65. open(temp_src, 'w').write(
  66. '''
  67. __asm__(
  68. " .section .text.btldr\\n"
  69. "btldr:\\n"
  70. " .incbin \\"%s\\"\\n"
  71. );
  72. ''' % escape_cpp(bootloader_bin[0])
  73. )
  74. bootloader_obj = env.Object(
  75. os.path.join("$BUILD_DIR", "bootloader_bin.o"),
  76. temp_src
  77. )
  78. # Add bootloader binary as dependency to the main firmware
  79. main_fw = os.path.join("$BUILD_DIR", env.subst("$PROGNAME$PROGSUFFIX"))
  80. env.Depends(bootloader_obj, bootloader_bin)
  81. env.Depends(main_fw, bootloader_obj)
  82. env.Append(LINKFLAGS = [bootloader_obj])