[PATCH 1/2] x86: video: Add a driver for QEMU bochs emulation

Bin Meng bmeng.cn at gmail.com
Thu May 11 13:23:01 CEST 2023


Hi Simon,

On Sun, Apr 30, 2023 at 10:32 AM Simon Glass <sjg at chromium.org> wrote:
>
> Bochs is convenient with QEMU on x86 since it does not require a video
> BIOS. Add a driver for it.
>
> Signed-off-by: Simon Glass <sjg at chromium.org>
> ---
>
>  drivers/video/Kconfig  |  30 ++++++++++
>  drivers/video/Makefile |   2 +
>  drivers/video/bochs.c  | 130 +++++++++++++++++++++++++++++++++++++++++
>  drivers/video/bochs.h  |  36 ++++++++++++
>  4 files changed, 198 insertions(+)
>  create mode 100644 drivers/video/bochs.c
>  create mode 100644 drivers/video/bochs.h
>
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index 9a95b7a4c792..5fd42807179f 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -278,6 +278,36 @@ config VIDCONSOLE_AS_NAME
>           possible to update the environment, the breakage may be confusing for
>           users. This option will be removed around the end of 2020.
>
> +config VIDEO_BOCHS
> +       bool "Enable Bochs video emulation for QEMU"
> +       depends on X86
> +       help
> +         Enable this to use the Boschs video support provided in the QEMU
> +         emulator. This appears as a PCI device which U-Boot can set up to
> +         provide a frame buffer.
> +
> +if VIDEO_BOCHS
> +
> +config VIDEO_BOCHS_SIZE_X
> +       int "Width of display (X resolution)"
> +       default 1280
> +       help
> +         Sets the width of the display.
> +
> +         These two options control the size of the display set up by QEMU.
> +         Typical sizes are 1024 x 768 or 1280 x 1024.
> +
> +config VIDEO_BOCHS_SIZE_Y
> +       int "High of display (Y resolution)"
> +       default 1024
> +       help
> +         Sets the height of the display.
> +
> +         These two options control the size of the display set up by QEMU.
> +         Typical sizes are 1024 x 768 or 1280 x 1024.
> +
> +endif
> +
>  config VIDEO_COREBOOT
>         bool "Enable coreboot framebuffer driver support"
>         depends on X86
> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> index a609e35d22e8..11d872ddf41d 100644
> --- a/drivers/video/Makefile
> +++ b/drivers/video/Makefile
> @@ -28,6 +28,8 @@ obj-$(CONFIG_VIDEO_LOGO) += u_boot_logo.o
>
>  endif
>
> +obj-$(CONFIG_VIDEO_BOCHS) += bochs.o
> +
>  obj-${CONFIG_EXYNOS_FB} += exynos/
>  obj-${CONFIG_VIDEO_ROCKCHIP} += rockchip/
>  obj-${CONFIG_VIDEO_STM32} += stm32/
> diff --git a/drivers/video/bochs.c b/drivers/video/bochs.c
> new file mode 100644
> index 000000000000..7ea29a0ed177
> --- /dev/null
> +++ b/drivers/video/bochs.c
> @@ -0,0 +1,130 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Modified from coreboot bochs.c
> + */
> +
> +#define LOG_CATEGORY   UCLASS_VIDEO
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <log.h>
> +#include <pci.h>
> +#include <video.h>
> +#include <asm/io.h>
> +#include <asm/mtrr.h>
> +#include <linux/sizes.h>
> +#include "bochs.h"
> +
> +static int xsize = CONFIG_VIDEO_BOCHS_SIZE_X;
> +static int ysize = CONFIG_VIDEO_BOCHS_SIZE_Y;
> +
> +static void bochs_write(void *mmio, int index, int val)
> +{
> +       writew(val, mmio + MMIO_BASE + index * 2);
> +}
> +
> +static int bochs_read(void *mmio, int index)
> +{
> +       return readw(mmio + MMIO_BASE + index * 2);
> +}
> +
> +static void bochs_vga_write(int index, uint8_t val)
> +{
> +       outb(val, VGA_INDEX);
> +}
> +
> +static int bochs_init_linear_fb(struct udevice *dev)
> +{
> +       struct video_uc_plat *plat = dev_get_uclass_plat(dev);
> +       struct video_priv *uc_priv = dev_get_uclass_priv(dev);
> +       ulong fb;
> +       void *mmio;
> +       int id, mem;
> +
> +       log_debug("probing %s at PCI %x\n", dev->name, dm_pci_get_bdf(dev));
> +       fb = dm_pci_read_bar32(dev, 0);
> +       if (!fb)
> +               return log_msg_ret("fb", -EIO);
> +
> +       /* MMIO bar supported since qemu 3.0+ */
> +       mmio = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_2, 0, 0, PCI_REGION_TYPE,
> +                             PCI_REGION_MEM);
> +
> +       if (!mmio)
> +               return log_msg_ret("map", -EIO);
> +
> +       log_debug("QEMU VGA: bochs @ %p: %d MiB FB at %lx\n", mmio, mem / SZ_1M,
> +                 fb);

mem is uninitialized yet at this point, until (see below)

> +
> +       /* bochs dispi detection */
> +       id = bochs_read(mmio, INDEX_ID);
> +       if ((id & 0xfff0) != ID0) {
> +               log_debug("ID mismatch\n");
> +               return -EPROTONOSUPPORT;
> +       }
> +       mem = bochs_read(mmio, INDEX_VIDEO_MEMORY_64K) * SZ_64K;

it reaches this line

> +
> +       uc_priv->xsize = xsize;
> +       uc_priv->ysize = ysize;
> +       uc_priv->bpix = VIDEO_BPP32;
> +
> +       /* setup video mode */
> +       bochs_write(mmio, INDEX_ENABLE,  0);
> +       bochs_write(mmio, INDEX_BANK,  0);
> +       bochs_write(mmio, INDEX_BPP, VNBITS(uc_priv->bpix));
> +       bochs_write(mmio, INDEX_XRES, xsize);
> +       bochs_write(mmio, INDEX_YRES, ysize);
> +       bochs_write(mmio, INDEX_VIRT_WIDTH, xsize);
> +       bochs_write(mmio, INDEX_VIRT_HEIGHT, ysize);
> +       bochs_write(mmio, INDEX_X_OFFSET, 0);
> +       bochs_write(mmio, INDEX_Y_OFFSET, 0);
> +       bochs_write(mmio, INDEX_ENABLE, ENABLED | LFB_ENABLED);
> +
> +       bochs_vga_write(0, 0x20);       /* disable blanking */
> +
> +       plat->base = fb;
> +
> +       return 0;
> +}
> +
> +static int bochs_video_probe(struct udevice *dev)
> +{
> +       int ret;
> +
> +       ret = bochs_init_linear_fb(dev);
> +       if (ret)
> +               return log_ret(ret);
> +
> +       return 0;
> +}
> +
> +static int bochs_video_bind(struct udevice *dev)
> +{
> +       struct video_uc_plat *uc_plat = dev_get_uclass_plat(dev);
> +
> +       /* Set the maximum supported resolution */
> +       uc_plat->size = 2560 * 1600 * 4;
> +       log_debug("%s: Frame buffer size %x\n", __func__, uc_plat->size);
> +
> +       return 0;
> +}
> +
> +static const struct udevice_id bochs_video_ids[] = {
> +       { .compatible = "bochs-fb" },
> +       { }
> +};
> +
> +U_BOOT_DRIVER(bochs_video) = {
> +       .name   = "bochs_video",
> +       .id     = UCLASS_VIDEO,
> +       .of_match = bochs_video_ids,
> +       .bind   = bochs_video_bind,
> +       .probe  = bochs_video_probe,
> +};
> +
> +static struct pci_device_id bochs_video_supported[] = {
> +       { PCI_DEVICE(0x1234, 0x1111) },
> +       { },
> +};
> +
> +U_BOOT_PCI_DEVICE(bochs_video, bochs_video_supported);
> diff --git a/drivers/video/bochs.h b/drivers/video/bochs.h
> new file mode 100644
> index 000000000000..4c8ec83a550e
> --- /dev/null
> +++ b/drivers/video/bochs.h
> @@ -0,0 +1,36 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Modified from coreboot bochs.c
> + */
> +
> +#ifndef __BOCHS_H
> +#define __BOCHS_H
> +
> +#define VGA_INDEX      0x3c0
> +
> +#define IOPORT_INDEX   0x01ce
> +#define IOPORT_DATA    0x01cf
> +
> +enum {
> +       INDEX_ID,
> +       INDEX_XRES,
> +       INDEX_YRES,
> +       INDEX_BPP,
> +       INDEX_ENABLE,
> +       INDEX_BANK,
> +       INDEX_VIRT_WIDTH,
> +       INDEX_VIRT_HEIGHT,
> +       INDEX_X_OFFSET,
> +       INDEX_Y_OFFSET,
> +       INDEX_VIDEO_MEMORY_64K
> +};
> +
> +#define ID0            0xb0c0
> +
> +#define ENABLED                BIT(0)
> +#define LFB_ENABLED    BIT(6)
> +#define NOCLEARMEM     BIT(7)
> +
> +#define MMIO_BASE      0x500
> +
> +#endif

Regards,
Bin


More information about the U-Boot mailing list