ramfb.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /*
  2. * early boot framebuffer in guest ram
  3. * configured using fw_cfg
  4. *
  5. * Copyright Red Hat, Inc. 2017
  6. *
  7. * Author:
  8. * Gerd Hoffmann <kraxel@redhat.com>
  9. *
  10. * This work is licensed under the terms of the GNU GPL, version 2 or later.
  11. * See the COPYING file in the top-level directory.
  12. */
  13. #include "qemu/osdep.h"
  14. #include "qapi/error.h"
  15. #include "hw/loader.h"
  16. #include "hw/display/ramfb.h"
  17. #include "hw/display/bochs-vbe.h" /* for limits */
  18. #include "ui/console.h"
  19. #include "system/reset.h"
  20. struct QEMU_PACKED RAMFBCfg {
  21. uint64_t addr;
  22. uint32_t fourcc;
  23. uint32_t flags;
  24. uint32_t width;
  25. uint32_t height;
  26. uint32_t stride;
  27. };
  28. typedef struct RAMFBCfg RAMFBCfg;
  29. struct RAMFBState {
  30. DisplaySurface *ds;
  31. uint32_t width, height;
  32. struct RAMFBCfg cfg;
  33. };
  34. static void ramfb_unmap_display_surface(pixman_image_t *image, void *unused)
  35. {
  36. void *data = pixman_image_get_data(image);
  37. uint32_t size = pixman_image_get_stride(image) *
  38. pixman_image_get_height(image);
  39. cpu_physical_memory_unmap(data, size, 0, 0);
  40. }
  41. static DisplaySurface *ramfb_create_display_surface(int width, int height,
  42. pixman_format_code_t format,
  43. hwaddr stride, hwaddr addr)
  44. {
  45. DisplaySurface *surface;
  46. hwaddr size, mapsize, linesize;
  47. void *data;
  48. if (width < 16 || width > VBE_DISPI_MAX_XRES ||
  49. height < 16 || height > VBE_DISPI_MAX_YRES ||
  50. format == 0 /* unknown format */)
  51. return NULL;
  52. linesize = width * PIXMAN_FORMAT_BPP(format) / 8;
  53. if (stride == 0) {
  54. stride = linesize;
  55. }
  56. mapsize = size = stride * (height - 1) + linesize;
  57. data = cpu_physical_memory_map(addr, &mapsize, false);
  58. if (size != mapsize) {
  59. cpu_physical_memory_unmap(data, mapsize, 0, 0);
  60. return NULL;
  61. }
  62. surface = qemu_create_displaysurface_from(width, height,
  63. format, stride, data);
  64. pixman_image_set_destroy_function(surface->image,
  65. ramfb_unmap_display_surface, NULL);
  66. return surface;
  67. }
  68. static void ramfb_fw_cfg_write(void *dev, off_t offset, size_t len)
  69. {
  70. RAMFBState *s = dev;
  71. DisplaySurface *surface;
  72. uint32_t fourcc, format, width, height;
  73. hwaddr stride, addr;
  74. width = be32_to_cpu(s->cfg.width);
  75. height = be32_to_cpu(s->cfg.height);
  76. stride = be32_to_cpu(s->cfg.stride);
  77. fourcc = be32_to_cpu(s->cfg.fourcc);
  78. addr = be64_to_cpu(s->cfg.addr);
  79. format = qemu_drm_format_to_pixman(fourcc);
  80. surface = ramfb_create_display_surface(width, height,
  81. format, stride, addr);
  82. if (!surface) {
  83. return;
  84. }
  85. s->width = width;
  86. s->height = height;
  87. qemu_free_displaysurface(s->ds);
  88. s->ds = surface;
  89. }
  90. void ramfb_display_update(QemuConsole *con, RAMFBState *s)
  91. {
  92. if (!s->width || !s->height) {
  93. return;
  94. }
  95. if (s->ds) {
  96. dpy_gfx_replace_surface(con, s->ds);
  97. s->ds = NULL;
  98. }
  99. /* simple full screen update */
  100. dpy_gfx_update_full(con);
  101. }
  102. static int ramfb_post_load(void *opaque, int version_id)
  103. {
  104. ramfb_fw_cfg_write(opaque, 0, 0);
  105. return 0;
  106. }
  107. const VMStateDescription ramfb_vmstate = {
  108. .name = "ramfb",
  109. .version_id = 1,
  110. .minimum_version_id = 1,
  111. .post_load = ramfb_post_load,
  112. .fields = (const VMStateField[]) {
  113. VMSTATE_BUFFER_UNSAFE(cfg, RAMFBState, 0, sizeof(RAMFBCfg)),
  114. VMSTATE_END_OF_LIST()
  115. }
  116. };
  117. RAMFBState *ramfb_setup(Error **errp)
  118. {
  119. FWCfgState *fw_cfg = fw_cfg_find();
  120. RAMFBState *s;
  121. if (!fw_cfg || !fw_cfg->dma_enabled) {
  122. error_setg(errp, "ramfb device requires fw_cfg with DMA");
  123. return NULL;
  124. }
  125. s = g_new0(RAMFBState, 1);
  126. rom_add_vga("vgabios-ramfb.bin");
  127. fw_cfg_add_file_callback(fw_cfg, "etc/ramfb",
  128. NULL, ramfb_fw_cfg_write, s,
  129. &s->cfg, sizeof(s->cfg), false);
  130. return s;
  131. }