qfw.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com>
  4. * (C) Copyright 2021 Asherah Connor <ashe@kivikakk.ee>
  5. */
  6. #include <dm.h>
  7. #include <env.h>
  8. #include <mapmem.h>
  9. #include <qfw.h>
  10. #include <stdlib.h>
  11. #include <dm/uclass.h>
  12. int qfw_get_dev(struct udevice **devp)
  13. {
  14. return uclass_first_device_err(UCLASS_QFW, devp);
  15. }
  16. int qfw_online_cpus(struct udevice *dev)
  17. {
  18. u16 nb_cpus;
  19. qfw_read_entry(dev, FW_CFG_NB_CPUS, 2, &nb_cpus);
  20. return le16_to_cpu(nb_cpus);
  21. }
  22. int qfw_read_firmware_list(struct udevice *dev)
  23. {
  24. int i;
  25. u32 count;
  26. struct fw_file *file;
  27. struct list_head *entry;
  28. struct qfw_dev *qdev = dev_get_uclass_priv(dev);
  29. /* don't read it twice */
  30. if (!list_empty(&qdev->fw_list))
  31. return 0;
  32. qfw_read_entry(dev, FW_CFG_FILE_DIR, 4, &count);
  33. if (!count)
  34. return 0;
  35. count = be32_to_cpu(count);
  36. for (i = 0; i < count; i++) {
  37. file = malloc(sizeof(*file));
  38. if (!file) {
  39. printf("error: allocating resource\n");
  40. goto err;
  41. }
  42. qfw_read_entry(dev, FW_CFG_INVALID,
  43. sizeof(struct fw_cfg_file), &file->cfg);
  44. file->addr = 0;
  45. list_add_tail(&file->list, &qdev->fw_list);
  46. }
  47. return 0;
  48. err:
  49. list_for_each(entry, &qdev->fw_list) {
  50. file = list_entry(entry, struct fw_file, list);
  51. free(file);
  52. }
  53. return -ENOMEM;
  54. }
  55. struct fw_file *qfw_find_file(struct udevice *dev, const char *name)
  56. {
  57. struct list_head *entry;
  58. struct fw_file *file;
  59. struct qfw_dev *qdev = dev_get_uclass_priv(dev);
  60. list_for_each(entry, &qdev->fw_list) {
  61. file = list_entry(entry, struct fw_file, list);
  62. if (!strcmp(file->cfg.name, name))
  63. return file;
  64. }
  65. return NULL;
  66. }
  67. struct fw_file *qfw_file_iter_init(struct udevice *dev,
  68. struct fw_cfg_file_iter *iter)
  69. {
  70. struct qfw_dev *qdev = dev_get_uclass_priv(dev);
  71. iter->entry = qdev->fw_list.next;
  72. iter->end = &qdev->fw_list;
  73. return list_entry((struct list_head *)iter->entry,
  74. struct fw_file, list);
  75. }
  76. struct fw_file *qfw_file_iter_next(struct fw_cfg_file_iter *iter)
  77. {
  78. iter->entry = ((struct list_head *)iter->entry)->next;
  79. return list_entry((struct list_head *)iter->entry,
  80. struct fw_file, list);
  81. }
  82. bool qfw_file_iter_end(struct fw_cfg_file_iter *iter)
  83. {
  84. return iter->entry == iter->end;
  85. }
  86. int qemu_fwcfg_setup_kernel(struct udevice *qfw_dev, ulong load_addr,
  87. ulong initrd_addr)
  88. {
  89. char *data_addr;
  90. u32 setup_size, kernel_size, cmdline_size, initrd_size;
  91. qfw_read_entry(qfw_dev, FW_CFG_SETUP_SIZE, 4, &setup_size);
  92. qfw_read_entry(qfw_dev, FW_CFG_KERNEL_SIZE, 4, &kernel_size);
  93. if (!kernel_size) {
  94. printf("fatal: no kernel available\n");
  95. return -ENOENT;
  96. }
  97. data_addr = map_sysmem(load_addr, 0);
  98. if (setup_size) {
  99. qfw_read_entry(qfw_dev, FW_CFG_SETUP_DATA,
  100. le32_to_cpu(setup_size), data_addr);
  101. data_addr += le32_to_cpu(setup_size);
  102. }
  103. qfw_read_entry(qfw_dev, FW_CFG_KERNEL_DATA,
  104. le32_to_cpu(kernel_size), data_addr);
  105. data_addr += le32_to_cpu(kernel_size);
  106. env_set_hex("filesize", le32_to_cpu(kernel_size));
  107. data_addr = map_sysmem(initrd_addr, 0);
  108. qfw_read_entry(qfw_dev, FW_CFG_INITRD_SIZE, 4, &initrd_size);
  109. if (!initrd_size) {
  110. printf("warning: no initrd available\n");
  111. } else {
  112. qfw_read_entry(qfw_dev, FW_CFG_INITRD_DATA,
  113. le32_to_cpu(initrd_size), data_addr);
  114. data_addr += le32_to_cpu(initrd_size);
  115. env_set_hex("filesize", le32_to_cpu(initrd_size));
  116. }
  117. qfw_read_entry(qfw_dev, FW_CFG_CMDLINE_SIZE, 4, &cmdline_size);
  118. if (cmdline_size) {
  119. qfw_read_entry(qfw_dev, FW_CFG_CMDLINE_DATA,
  120. le32_to_cpu(cmdline_size), data_addr);
  121. /*
  122. * if kernel cmdline only contains '\0', (e.g. no -append
  123. * when invoking qemu), do not update bootargs
  124. */
  125. if (*data_addr) {
  126. if (env_set("bootargs", data_addr) < 0)
  127. printf("warning: unable to change bootargs\n");
  128. }
  129. }
  130. printf("loading kernel to address %lx size %x", load_addr,
  131. le32_to_cpu(kernel_size));
  132. if (initrd_size)
  133. printf(" initrd %lx size %x\n", initrd_addr,
  134. le32_to_cpu(initrd_size));
  135. else
  136. printf("\n");
  137. return 0;
  138. }