Skip to content
Oeiuwq Faith Blog OpenSource Porfolio

humphd/browser-vm

A small Linux x86 VM meant for use in the browser

humphd/browser-vm.json
{
"createdAt": "2019-02-06T22:50:15Z",
"defaultBranch": "master",
"description": "A small Linux x86 VM meant for use in the browser",
"fullName": "humphd/browser-vm",
"homepage": null,
"language": "Dockerfile",
"name": "browser-vm",
"pushedAt": "2023-05-27T08:55:34Z",
"stargazersCount": 201,
"topics": [
"browser",
"buildroot",
"docker",
"vm",
"x86"
],
"updatedAt": "2025-12-19T20:12:05Z",
"url": "https://github.com/humphd/browser-vm"
}

A custom Buildroot config for a Linux x86 VM, meant to be run in the browser as part of browser-shell. The resulting Linux ISO is meant to be run under emulation in the browser via v86, and includes:

  • a custom Linux 4.15 kernel, which strips out many unnecessary drivers, modules, etc. and adds Plan 9 filesystem sharing
  • a root filesystem and Unix commands via BusyBox
  • an ISO-based bootloader (i.e., we create a “DVD” that is booted by v86)

Following the Buildroot customization docs we create a folder buildroot-v86/ with all the necessary config files, filesystem overlay, and scripts necessary to build our distribution.

To build the Docker image use the build.sh script, or:

Terminal window
$ docker build -t buildroot .

And then to run the build:

Terminal window
$ docker run \
--rm \
--name build-v86 \
-v $PWD/dist:/build \
-v $PWD/buildroot-v86/:/buildroot-v86 \
buildroot

NOTE: we define two volumes to allow the container to access the v86 config, and also to write the ISO once complete. In the above I’ve used $PWD, but you can use any absolute path.

When the build completes, an ISO file will be places in ./dist/v86-linux.iso in your source tree (i.e., outside the container).

If you need to re-configure things, instead of just running the build, do the following:

Terminal window
$ docker run \
--rm \
--name build-v86 \
-v $PWD/dist:/build \
-v $PWD/buildroot-v86/:/buildroot-v86 \
-ti \
--entrypoint "bash" \
buildroot

Now in the resulting bash terminal, you can run make menuconfig and other make commands.

We define a v86 buildroot “board” via the following files and directories:

+-- board/
+-- v86
+-- linux.config # our custom Linux kernel config (make linux-menuconfig)
+-- post_build.sh # script to copy ISO file out of docker container
+-- rootfs_overlay/ # overrides for files in the root filesystem
+-- etc/
+-- inittab # we setup a ttyS0 console terminal to auto-login
+-- fstab # we auto-mount the Plan 9 Filer filesystem to /mnt
+-- configs/
+-- v86_defconfig # our custom buildroot config (make menuconfig)
+-- Config.in # empty, but required https://buildroot.org/downloads/manual/manual.html#outside-br-custom
+-- external.mk # empty, but required https://buildroot.org/downloads/manual/manual.html#outside-br-custom
+-- external.desc # our v86 board config for make
+-- build-v86.sh # entrypoint for Docker to run our build

If you need or want to update these config files, do the following:

Terminal window
$ make BR2_EXTERNAL=/buildroot-v86 v86_defconfig
$ make menuconfig
...
$ make savedefconfig
$ make linux-menuconfig
...
$ make linux-savedefconfig

These are the options I set when configuring buildroot for v86. I’m only specifying the things I set.

Terminal window
$ cd buildroot-2018.02
$ make menuconfig

Then follow these config steps in the buildroot config menu (NOTE: these docs may have drifted from the actual config in the source, so consult that first):

  • Target Architecture: i386
  • Target Architecture Variant: pentium mobile (Pentium with MMX, SSE)
  • Enable compiler cache (not strictly necessary, but helps with rebuilds)
  • C library: uLibc-ng (I’d like to experiment with musl too)
  • remount root filesystem read-write during boot (I think this is unnecessary)
  • Root filesystem overlay directories: /build/overlay-fs (for etc/inittab)
  • Linux Kernel: true
  • Defconfig name: i386
  • Kernel binary format: bzImage (vmlinux seemed to break on boot)

Need to figure this out. I tried adding imagemagik, git, uemacs, but they are all adding too much size to the image.

  • cpio the root filesystem (for use as an initial RAM filesystem)
  • initial RAM filesystem linked into the linux kernel (not sure I need this, trying without…)
  • iso image
    • Use initrd
  • tar the root filesystem Compression method (no compression)
  • syslinux
    • install isolinux

Now configure the Linux Kernel:

$ make linux-menuconfig

And set the following options to accomplish this:

CONFIG_NET_9P=y
CONFIG_NET_9P_VIRTIO=y
CONFIG_9P_FS=y
CONFIG_9P_FS_POSIX_ACL=y
CONFIG_PCI=y
CONFIG_VIRTIO_PCI=y
CONFIG_PCI=y
CONFIG_VIRTIO_PCI=y
  • Processor family (Pentium-Pro) also tried Pentium M before.
  • PCI Debugging: true (I want to see what’s happening with PCI errors, normally not needed)
  • Plan 9 Resource Sharing Support (9P2000) (built into kernel * vs. M)
    • 9P Virtio Transport (* - make this is on, it won’t exist if virtio is off)
    • Debug information (* - optional)
  • Virtio drivers
    • PCI driver for virtio devices (built into kernel * vs. M)
      • Support for legacy virtio draft 0.9.X and older devices (New)
    • Platform bus driver for memory mapped virtio devices (* vs. M) - not sure I need this…
      • Memory mapped virtio devices parameter parsing - or this…
  • Caches

    • General filesystem local caching manager (*)
      • Filesystem caching on files (*)
  • Network File Systems

    • Plan 9 Resource Sharing Support (9P2000) (*)
      • Enable 9P client caching support
      • 9P Posic Access Control Lists

Now run make

When it finishes, the built image is in ./output/images.