bcmfw.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. *
  4. * BlueZ - Bluetooth protocol stack for Linux
  5. *
  6. * Copyright (C) 2012-2013 Intel Corporation
  7. *
  8. *
  9. */
  10. #ifdef HAVE_CONFIG_H
  11. #include <config.h>
  12. #endif
  13. #define _GNU_SOURCE
  14. #include <stdio.h>
  15. #include <errno.h>
  16. #include <fcntl.h>
  17. #include <unistd.h>
  18. #include <string.h>
  19. #include <getopt.h>
  20. #include <stdlib.h>
  21. #include <stdint.h>
  22. #include <sys/stat.h>
  23. #include <sys/mman.h>
  24. static void print_cmd(uint16_t opcode, const uint8_t *buf, uint8_t plen)
  25. {
  26. switch (opcode) {
  27. case 0xfc4c:
  28. printf(" Write_RAM [address=0x%08x]",
  29. buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24);
  30. break;
  31. case 0xfc4e:
  32. printf(" Launch_RAM [address=0x%08x]",
  33. buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24);
  34. break;
  35. }
  36. }
  37. static void analyze_memory(const uint8_t *buf, size_t len)
  38. {
  39. const uint8_t *ptr = buf;
  40. while (len >= 3) {
  41. uint16_t opcode = ptr[0] | ptr[1] << 8;
  42. uint8_t plen = ptr[2];
  43. ptr += 3;
  44. len -= 3;
  45. if (len < plen) {
  46. fprintf(stderr, "Corrupted file\n");
  47. break;
  48. }
  49. printf("opcode=0x%04x plen=%-3u", opcode, plen);
  50. print_cmd(opcode, ptr + 3, plen);
  51. printf("\n");
  52. ptr += plen;
  53. len -= plen;
  54. }
  55. }
  56. static void analyze_file(const char *pathname)
  57. {
  58. struct stat st;
  59. void *map;
  60. int fd;
  61. printf("Analyzing %s\n", pathname);
  62. fd = open(pathname, O_RDONLY | O_CLOEXEC);
  63. if (fd < 0) {
  64. perror("Failed to open file");
  65. return;
  66. }
  67. if (fstat(fd, &st) < 0) {
  68. fprintf(stderr, "Failed get file size\n");
  69. close(fd);
  70. return;
  71. }
  72. if (st.st_size == 0) {
  73. fprintf(stderr, "Empty file\n");
  74. close(fd);
  75. return;
  76. }
  77. map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
  78. if (!map || map == MAP_FAILED) {
  79. fprintf(stderr, "Failed to map file\n");
  80. close(fd);
  81. return;
  82. }
  83. analyze_memory(map, st.st_size);
  84. munmap(map, st.st_size);
  85. close(fd);
  86. }
  87. static void usage(void)
  88. {
  89. printf("Broadcom Bluetooth firmware analyzer\n"
  90. "Usage:\n");
  91. printf("\tbcmfw [options] <file>\n");
  92. printf("Options:\n"
  93. "\t-h, --help Show help options\n");
  94. }
  95. static const struct option main_options[] = {
  96. { "version", no_argument, NULL, 'v' },
  97. { "help", no_argument, NULL, 'h' },
  98. { }
  99. };
  100. int main(int argc, char *argv[])
  101. {
  102. int i;
  103. for (;;) {
  104. int opt;
  105. opt = getopt_long(argc, argv, "vh", main_options, NULL);
  106. if (opt < 0)
  107. break;
  108. switch (opt) {
  109. case 'v':
  110. printf("%s\n", VERSION);
  111. return EXIT_SUCCESS;
  112. case 'h':
  113. usage();
  114. return EXIT_SUCCESS;
  115. default:
  116. return EXIT_FAILURE;
  117. }
  118. }
  119. if (argc - optind < 1) {
  120. fprintf(stderr, "No input firmware files provided\n");
  121. return EXIT_FAILURE;
  122. }
  123. for (i = optind; i < argc; i++)
  124. analyze_file(argv[i]);
  125. return EXIT_SUCCESS;
  126. }