ramfb.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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 "sysemu/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. struct RAMFBState {
  29. DisplaySurface *ds;
  30. uint32_t width, height;
  31. struct RAMFBCfg cfg;
  32. };
  33. static void ramfb_unmap_display_surface(pixman_image_t *image, void *unused)
  34. {
  35. void *data = pixman_image_get_data(image);
  36. uint32_t size = pixman_image_get_stride(image) *
  37. pixman_image_get_height(image);
  38. cpu_physical_memory_unmap(data, size, 0, 0);
  39. }
  40. static DisplaySurface *ramfb_create_display_surface(int width, int height,
  41. pixman_format_code_t format,
  42. hwaddr stride, hwaddr addr)
  43. {
  44. DisplaySurface *surface;
  45. hwaddr size, mapsize, linesize;
  46. void *data;
  47. if (width < 16 || width > VBE_DISPI_MAX_XRES ||
  48. height < 16 || height > VBE_DISPI_MAX_YRES ||
  49. format == 0 /* unknown format */)
  50. return NULL;
  51. linesize = width * PIXMAN_FORMAT_BPP(format) / 8;
  52. if (stride == 0) {
  53. stride = linesize;
  54. }
  55. mapsize = size = stride * (height - 1) + linesize;
  56. data = cpu_physical_memory_map(addr, &mapsize, false);
  57. if (size != mapsize) {
  58. cpu_physical_memory_unmap(data, mapsize, 0, 0);
  59. return NULL;
  60. }
  61. surface = qemu_create_displaysurface_from(width, height,
  62. format, stride, data);
  63. pixman_image_set_destroy_function(surface->image,
  64. ramfb_unmap_display_surface, NULL);
  65. return surface;
  66. }
  67. static void ramfb_fw_cfg_write(void *dev, off_t offset, size_t len)
  68. {
  69. RAMFBState *s = dev;
  70. DisplaySurface *surface;
  71. uint32_t fourcc, format, width, height;
  72. hwaddr stride, addr;
  73. width = be32_to_cpu(s->cfg.width);
  74. height = be32_to_cpu(s->cfg.height);
  75. stride = be32_to_cpu(s->cfg.stride);
  76. fourcc = be32_to_cpu(s->cfg.fourcc);
  77. addr = be64_to_cpu(s->cfg.addr);
  78. format = qemu_drm_format_to_pixman(fourcc);
  79. surface = ramfb_create_display_surface(width, height,
  80. format, stride, addr);
  81. if (!surface) {
  82. return;
  83. }
  84. s->width = width;
  85. s->height = height;
  86. s->ds = surface;
  87. }
  88. void ramfb_display_update(QemuConsole *con, RAMFBState *s)
  89. {
  90. if (!s->width || !s->height) {
  91. return;
  92. }
  93. if (s->ds) {
  94. dpy_gfx_replace_surface(con, s->ds);
  95. s->ds = NULL;
  96. }
  97. /* simple full screen update */
  98. dpy_gfx_update_full(con);
  99. }
  100. RAMFBState *ramfb_setup(Error **errp)
  101. {
  102. FWCfgState *fw_cfg = fw_cfg_find();
  103. RAMFBState *s;
  104. if (!fw_cfg || !fw_cfg->dma_enabled) {
  105. error_setg(errp, "ramfb device requires fw_cfg with DMA");
  106. return NULL;
  107. }
  108. s = g_new0(RAMFBState, 1);
  109. rom_add_vga("vgabios-ramfb.bin");
  110. fw_cfg_add_file_callback(fw_cfg, "etc/ramfb",
  111. NULL, ramfb_fw_cfg_write, s,
  112. &s->cfg, sizeof(s->cfg), false);
  113. return s;
  114. }