summary refs log tree commit diff
path: root/pkgs/os-specific/linux/chromium-os
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/os-specific/linux/chromium-os')
-rw-r--r--pkgs/os-specific/linux/chromium-os/common-mk/0001-common-mk-don-t-leak-source-absolute-paths.patch139
-rw-r--r--pkgs/os-specific/linux/chromium-os/common-mk/0002-common-mk-.gn-don-t-hardcode-env-path.patch23
-rw-r--r--pkgs/os-specific/linux/chromium-os/common-mk/0003-Revert-common-mk-Suppress-Wrange-loop-analysis-warni.patch72
-rw-r--r--pkgs/os-specific/linux/chromium-os/common-mk/default.nix119
-rw-r--r--pkgs/os-specific/linux/chromium-os/crosvm/default-seccomp-policy-dir.diff15
-rw-r--r--pkgs/os-specific/linux/chromium-os/crosvm/default.nix83
-rw-r--r--pkgs/os-specific/linux/chromium-os/dbus-properties/default.nix9
-rw-r--r--pkgs/os-specific/linux/chromium-os/default.nix63
-rw-r--r--pkgs/os-specific/linux/chromium-os/libqmi/default.nix26
-rw-r--r--pkgs/os-specific/linux/chromium-os/modem-manager/default.nix31
-rw-r--r--pkgs/os-specific/linux/chromium-os/modem-manager/next.nix24
-rw-r--r--pkgs/os-specific/linux/chromium-os/modp_b64/default.nix23
-rw-r--r--pkgs/os-specific/linux/chromium-os/protofiles/default.nix34
-rw-r--r--pkgs/os-specific/linux/chromium-os/sommelier/0004-sommelier-don-t-leak-source-absolute-paths.patch25
-rw-r--r--pkgs/os-specific/linux/chromium-os/sommelier/0005-sommelier-use-stable-xdg-shell-protocol.patch1748
-rw-r--r--pkgs/os-specific/linux/chromium-os/sommelier/0006-sommelier-make-building-demos-optional.patch100
-rw-r--r--pkgs/os-specific/linux/chromium-os/sommelier/default.nix38
-rwxr-xr-xpkgs/os-specific/linux/chromium-os/update.py115
-rw-r--r--pkgs/os-specific/linux/chromium-os/upstream-info.json60
-rw-r--r--pkgs/os-specific/linux/chromium-os/vm_protos/default.nix31
20 files changed, 2778 insertions, 0 deletions
diff --git a/pkgs/os-specific/linux/chromium-os/common-mk/0001-common-mk-don-t-leak-source-absolute-paths.patch b/pkgs/os-specific/linux/chromium-os/common-mk/0001-common-mk-don-t-leak-source-absolute-paths.patch
new file mode 100644
index 00000000000..741b50af1b4
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/common-mk/0001-common-mk-don-t-leak-source-absolute-paths.patch
@@ -0,0 +1,139 @@
+From 56d3fe9520c1ef2a6400939f4deae06d9b5cdfc2 Mon Sep 17 00:00:00 2001
+From: Alyssa Ross <hi@alyssa.is>
+Date: Sun, 24 Nov 2019 16:56:11 +0000
+Subject: [PATCH 1/6] common-mk: don't leak source-absolute paths
+
+Source-absolute paths like //vm_tools/whatever were being leaked to
+subprocesses, which of course didn't know how to understand them.
+With this patch, source-absolute paths are only used to tell GN the
+outputs, and normal Unix paths are passed to subprocesses.
+---
+ common-mk/external_dependencies/BUILD.gn |  3 ++-
+ common-mk/pkg_config.gni                 |  7 +++----
+ common-mk/proto_library.gni              | 21 +++++++++++----------
+ 3 files changed, 16 insertions(+), 15 deletions(-)
+
+diff --git a/common-mk/external_dependencies/BUILD.gn b/common-mk/external_dependencies/BUILD.gn
+index 61f571b38..4cb7b93cf 100644
+--- a/common-mk/external_dependencies/BUILD.gn
++++ b/common-mk/external_dependencies/BUILD.gn
+@@ -47,6 +47,7 @@ genxml2cpp("dbus-proxies") {
+ action("cloud_policy_proto_generator") {
+   policy_resources_dir = "${sysroot}/usr/share/policy_resources"
+   proto_out_dir = "${target_gen_dir}/proto"
++  cloud_policy_protobuf_dir = rebase_path(proto_out_dir)
+   policy_tools_dir = "${sysroot}/usr/share/policy_tools"
+ 
+   script = "${policy_tools_dir}/generate_policy_source.py"
+@@ -58,7 +59,7 @@ action("cloud_policy_proto_generator") {
+     "${proto_out_dir}/cloud_policy.proto",
+   ]
+   args = [
+-    "--cloud-policy-protobuf=${proto_out_dir}/cloud_policy.proto",
++    "--cloud-policy-protobuf=${cloud_policy_protobuf_dir}/cloud_policy.proto",
+     "--chrome-version-file=${policy_resources_dir}/VERSION",
+     "--target-platform=chromeos",
+     "--policy-templates-file=${policy_resources_dir}/policy_templates.json",
+diff --git a/common-mk/pkg_config.gni b/common-mk/pkg_config.gni
+index af3c3fb4c..151c49e56 100644
+--- a/common-mk/pkg_config.gni
++++ b/common-mk/pkg_config.gni
+@@ -81,12 +81,11 @@ template("generate_pkg_config") {
+     if (!defined(output_name)) {
+       output_name = name
+     }
+-    outputs = [
+-      "${target_out_dir}/${output_name}.pc",
+-    ]
++    lib_path = "${target_out_dir}/${output_name}.pc"
++    outputs = [ lib_path ]
+ 
+     script = "//common-mk/generate-pc.py"
+-    args = [ "--output" ] + outputs + [ "--name=" + name ]
++    args = [ "--output", rebase_path(lib_path), "--name=" + name ]
+     if (defined(description)) {
+       args += [ "--description=" + description ]
+     }
+diff --git a/common-mk/proto_library.gni b/common-mk/proto_library.gni
+index 7fcb08341..692704288 100644
+--- a/common-mk/proto_library.gni
++++ b/common-mk/proto_library.gni
+@@ -56,7 +56,7 @@ template("proto_library") {
+ 
+     cc_dir = "${root_gen_dir}/${proto_out_dir}"
+     proto_in_dir = rebase_path(proto_in_dir)
+-    proto_out_dir = rebase_path(proto_out_dir)
++    proto_out_dir = rebase_path(cc_dir)
+ 
+     proto_lib_dirs = [
+       proto_in_dir,
+@@ -94,24 +94,23 @@ template("proto_library") {
+     args += [ "${proto_in_dir}/{{source_name_part}}.proto" ]
+     outputs = []
+     if (gen_python) {
+-      python_dir = "${root_gen_dir}/${proto_out_dir}/py"
+       args += [
+         "--python_out",
+-        "${python_dir}",
++        "${proto_out_dir}/py",
+       ]
+-      outputs += [ "${python_dir}/{{source_name_part}}_pb.py" ]
++      outputs += [ "${cc_dir}/py/{{source_name_part}}_pb.py" ]
+     }
+     if (gen_grpc) {
+       if (gen_grpc_gmock) {
+-        args += [ "--grpc_out=generate_mock_code=true:${cc_dir}" ]
++        args += [ "--grpc_out=generate_mock_code=true:${proto_out_dir}" ]
+         outputs += [ "${cc_dir}/{{source_name_part}}_mock.grpc.pb.h" ]
+       } else {
+-        args += [ "--grpc_out=${cc_dir}" ]
++        args += [ "--grpc_out=${proto_out_dir}" ]
+       }
+       grpc_cpp_plugin = "/usr/bin/grpc_cpp_plugin"
+       args += [
+         "--plugin=protoc-gen-grpc=${grpc_cpp_plugin}",
+-        "--cpp_out=${gen_cpp_mode}${cc_dir}",
++        "--cpp_out=${gen_cpp_mode}${proto_out_dir}",
+       ]
+       outputs += [
+         "${cc_dir}/{{source_name_part}}.grpc.pb.cc",
+@@ -121,7 +120,7 @@ template("proto_library") {
+       ]
+     }
+     if (!gen_grpc && !gen_python) {
+-      args += [ "--cpp_out=${gen_cpp_mode}${cc_dir}" ]
++      args += [ "--cpp_out=${gen_cpp_mode}${proto_out_dir}" ]
+       outputs += [
+         "${cc_dir}/{{source_name_part}}.pb.cc",
+         "${cc_dir}/{{source_name_part}}.pb.h",
+@@ -208,7 +207,9 @@ template("goproto_library") {
+     # otherwise file descriptor var name will conflict.
+     # cf) https://github.com/golang/protobuf/issues/109
+ 
++    cc_dir = "${root_gen_dir}/${proto_out_dir}"
+     proto_in_dir = rebase_path(invoker.proto_in_dir)
++    proto_out_dir = rebase_path(cc_dir)
+ 
+     # Build protoc command line to run.
+     script = "//common-mk/file_generator_wrapper.py"
+@@ -224,7 +225,7 @@ template("goproto_library") {
+       "--proto_path",
+       "${sysroot}/usr/share/proto",
+       "--go_out",
+-      "${go_out_prefix}${root_gen_dir}/${proto_out_dir}",
++      "${go_out_prefix}${proto_out_dir}",
+     ]
+     foreach(source, sources) {
+       args += [ rebase_path(source) ]
+@@ -234,7 +235,7 @@ template("goproto_library") {
+     outputs = []
+     foreach(source, invoker.sources) {
+       name = get_path_info(source, "name")
+-      outputs += [ "${root_gen_dir}/${proto_out_dir}/${name}.pb.go" ]
++      outputs += [ "${cc_dir}/${name}.pb.go" ]
+     }
+   }
+ }
+-- 
+2.25.1
+
diff --git a/pkgs/os-specific/linux/chromium-os/common-mk/0002-common-mk-.gn-don-t-hardcode-env-path.patch b/pkgs/os-specific/linux/chromium-os/common-mk/0002-common-mk-.gn-don-t-hardcode-env-path.patch
new file mode 100644
index 00000000000..51c15dcd4cb
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/common-mk/0002-common-mk-.gn-don-t-hardcode-env-path.patch
@@ -0,0 +1,23 @@
+From ec1afec90fd8e391b93f53f0abd8bc11cdba0a32 Mon Sep 17 00:00:00 2001
+From: Alyssa Ross <hi@alyssa.is>
+Date: Sun, 24 Nov 2019 17:20:46 +0000
+Subject: [PATCH 2/6] common-mk: .gn: don't hardcode env path
+
+This is needlessly non-portable.
+---
+ .gn | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/.gn b/.gn
+index e7dba8c91..e29fcd61e 100644
+--- a/.gn
++++ b/.gn
+@@ -7,4 +7,4 @@ root = "//common-mk/gn_root/:"
+ 
+ # This makes all scripts run by gn respect the shebang setting of the script.
+ # Otherwise, the default is to always use `python`.
+-script_executable = "/usr/bin/env"
++script_executable = "env"
+-- 
+2.25.1
+
diff --git a/pkgs/os-specific/linux/chromium-os/common-mk/0003-Revert-common-mk-Suppress-Wrange-loop-analysis-warni.patch b/pkgs/os-specific/linux/chromium-os/common-mk/0003-Revert-common-mk-Suppress-Wrange-loop-analysis-warni.patch
new file mode 100644
index 00000000000..d3d4e915163
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/common-mk/0003-Revert-common-mk-Suppress-Wrange-loop-analysis-warni.patch
@@ -0,0 +1,72 @@
+From b3add805d98e01488d71cbad51206f3a4949bb1c Mon Sep 17 00:00:00 2001
+From: Denis Nikitin <denik@chromium.org>
+Date: Wed, 5 Feb 2020 18:43:38 +0000
+Subject: [PATCH 3/6] Revert "common-mk: Suppress -Wrange-loop-analysis
+ warning"
+
+This reverts commit 09298dce8d31b5744a83784d027a3fd1e312eb6d.
+
+Reason for revert: <The warning is fixed in the upstream starting from r382025>
+
+Original change's description:
+> common-mk: Suppress -Wrange-loop-analysis warning
+>
+> Disable range-loop-analysis warning in platform2 to unblock llvm-next
+> builds failing with the following warning in libbrillo which can't be
+> easily fixed:
+>
+> data_serialization.h:471:20: error: loop variable 'element' is always a
+> copy because the range of type 'const std::vector<bool, allocator<bool>
+> >' does not return a reference [-Werror,-Wrange-loop-analysis]
+>   for (const auto& element : value) {
+>                                 ^
+> use non-reference type
+> 'std::__1::__bit_const_reference<std::__1::vector<bool,
+> std::__1::allocator<bool> > >'
+>
+> BUG=chromium:1042979
+> TEST=emerge-kevin libbrillo
+>
+> Change-Id: If5b70cb1a836df325d3683217be4c841fc7a5516
+> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2008102
+> Reviewed-by: Manoj Gupta <manojgupta@chromium.org>
+> Reviewed-by: Chris McDonald <cjmcdonald@chromium.org>
+> Tested-by: Manoj Gupta <manojgupta@chromium.org>
+
+Bug: chromium:1042979
+Change-Id: Ib86d9f0d61b703d391f60824d8d2ef47eb60f345
+Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2039651
+Reviewed-by: Mike Frysinger <vapier@chromium.org>
+Reviewed-by: Chris McDonald <cjmcdonald@chromium.org>
+Commit-Queue: Denis Nikitin <denik@chromium.org>
+Tested-by: Denis Nikitin <denik@chromium.org>
+(cherry picked from commit f53a0117ded343295015e81db68bbe878fae5fac)
+---
+ common-mk/BUILD.gn | 4 ----
+ 1 file changed, 4 deletions(-)
+
+diff --git a/common-mk/BUILD.gn b/common-mk/BUILD.gn
+index 7c0601b18..dc02a6979 100644
+--- a/common-mk/BUILD.gn
++++ b/common-mk/BUILD.gn
+@@ -53,7 +53,6 @@ config("compiler_defaults") {
+   cflags = [
+     "-Wall",
+     "-Wunused",
+-
+     # We use C99 array designators in C++ code.  Our compilers support this
+     # extension since C++ has no equivalent yet (as of C++20).
+     "-Wno-c99-designator",
+@@ -65,9 +64,6 @@ config("compiler_defaults") {
+     "-fvisibility=internal",
+     "-Wa,--noexecstack",
+     "-Wimplicit-fallthrough",
+-
+-    # TODO(crbug.com/1042979): Verify the warning when the issue gets fixed.
+-    "-Wno-range-loop-analysis",
+   ]
+   cflags_c = [ "-std=gnu11" ] + external_cppflags + external_cxxflags
+   cflags_cc = [ "-std=gnu++14" ] + external_cppflags + external_cxxflags
+-- 
+2.25.1
+
diff --git a/pkgs/os-specific/linux/chromium-os/common-mk/default.nix b/pkgs/os-specific/linux/chromium-os/common-mk/default.nix
new file mode 100644
index 00000000000..f07e418b56f
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/common-mk/default.nix
@@ -0,0 +1,119 @@
+{ stdenv, lib, fetchFromGitiles, upstreamInfo, gn, pkgconfig, python3, ninja
+# , libchrome
+}:
+
+{ platformSubdir
+
+# Mandatory, unlike in mkDerivation, because Google doesn't provide
+# install tasks and just does that in their ebuilds.
+, installPhase
+
+# src allows an out-of-tree (i.e., out-of-platform2) package to be
+# built with common-mk.  patches will be applied to `src` -- to patch
+# platform2 itself use platform2Patches.
+, src ? null, platform2Patches ? []
+
+# gnArgs allows structured data (attribute sets) to be serialized and
+# passed to gn, unlike gnFlags provided by gn's setupHook, which is a
+# flat list of strings.
+, gnArgs ? {}, gnFlags ? [], use ? {}
+
+, postUnpack ? "", prePatch ? "", postPatch ? ""
+, nativeBuildInputs ? []
+, meta ? {}
+, ... } @ args:
+
+let
+  platform2 = fetchFromGitiles upstreamInfo.components."chromiumos/platform2";
+
+  attrsToGnList = lib.mapAttrsToList (name: value: "${name}=${toGn value}");
+
+  toGn = value:
+    if lib.isAttrs value then
+      "{${lib.concatStringsSep " " (attrsToGnList value)}}"
+    else
+      builtins.toJSON value;
+in
+
+stdenv.mkDerivation ({
+  pname = lib.last (lib.splitString "/" platformSubdir);
+  inherit (upstreamInfo) version;
+
+  srcs = [ platform2 ] ++ lib.optional (src != null) src;
+  sourceRoot = "platform2";
+
+  postUnpack = lib.optionalString (src != null) ''
+    ln -s ../${src.name} $sourceRoot/${platformSubdir}
+    chmod -R +w ${src.name}
+  '' + postUnpack;
+
+  prePatch = ''
+    pushd ${platformSubdir}
+  '' + prePatch;
+
+  postPatch = ''
+    popd
+    ${lib.concatMapStrings (patch: ''
+      echo applying patch ${patch}
+      patch -p1 < ${patch} 
+    '') ([
+      ./0001-common-mk-don-t-leak-source-absolute-paths.patch
+      ./0002-common-mk-.gn-don-t-hardcode-env-path.patch
+      ./0003-Revert-common-mk-Suppress-Wrange-loop-analysis-warni.patch
+    ] ++ platform2Patches)}
+
+    patchShebangs common-mk
+  '' + (lib.optionalString (!stdenv.cc.isClang) ''
+    substituteInPlace common-mk/BUILD.gn \
+        --replace '"-Wno-c99-designator",' ""
+  '') + postPatch;
+
+  nativeBuildInputs = [ gn pkgconfig python3 ninja ] ++ nativeBuildInputs;
+
+  gnFlags = (attrsToGnList ({
+    ar = "ar";
+    cc = "cc";
+    cxx = "c++";
+    # libbase_ver = libchrome.version;
+    libdir = placeholder "out";
+    pkg_config = "pkg-config";
+    platform2_root = ".";
+    platform_subdir = platformSubdir;
+    use = {
+      amd64 = stdenv.targetPlatform.isx86_64;
+      arm = stdenv.targetPlatform.isAarch32 || stdenv.targetPlatform.isAarch64;
+      asan = false;
+      coverage = false;
+      cros_host = false;
+      crypto = false;
+      dbus = false;
+      device_mapper = false;
+      fuzzer = false;
+      mojo = false;
+      profiling = false;
+      tcmalloc = false;
+      test = false;
+      timers = false;
+      udev = false;
+    } // use;
+  } // gnArgs)) ++ gnFlags;
+
+  passthru.updateScript = ../update.py;
+
+  meta = {
+    homepage =
+      if src == null then
+        "${platform2.meta.homepage}/+/HEAD/${platformSubdir}"
+      else
+        src.meta.homepage;
+    platform = lib.platforms.linux;
+  } // lib.optionalAttrs (src == null) {
+    license = lib.licenses.bsd3;
+  } // meta;
+} // (builtins.removeAttrs args [
+  "src"
+  "gnArgs" "gnFlags" "use"
+  "postUnpack" "prePatch" "postPatch"
+  "nativeBuildInputs"
+  "meta"
+]))
diff --git a/pkgs/os-specific/linux/chromium-os/crosvm/default-seccomp-policy-dir.diff b/pkgs/os-specific/linux/chromium-os/crosvm/default-seccomp-policy-dir.diff
new file mode 100644
index 00000000000..f1aa50ee102
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/crosvm/default-seccomp-policy-dir.diff
@@ -0,0 +1,15 @@
+diff --git a/src/crosvm.rs b/src/crosvm.rs
+index b7055df..5989c87 100644
+--- a/src/crosvm.rs
++++ b/src/crosvm.rs
+@@ -141,7 +141,9 @@ impl Default for Config {
+             x_display: None,
+             shared_dirs: Vec::new(),
+             sandbox: !cfg!(feature = "default-no-sandbox"),
+-            seccomp_policy_dir: PathBuf::from(SECCOMP_POLICY_DIR),
++            seccomp_policy_dir: PathBuf::from(
++                option_env!("DEFAULT_SECCOMP_POLICY_DIR").unwrap_or(SECCOMP_POLICY_DIR),
++            ),
+             seccomp_log_failures: false,
+             cras_audio: false,
+             cras_capture: false,
diff --git a/pkgs/os-specific/linux/chromium-os/crosvm/default.nix b/pkgs/os-specific/linux/chromium-os/crosvm/default.nix
new file mode 100644
index 00000000000..3813e3eb75a
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/crosvm/default.nix
@@ -0,0 +1,83 @@
+{ stdenv, lib, rustPlatform, fetchFromGitiles, upstreamInfo
+, pkgconfig, minijail, dtc, libusb1, libcap, linux
+}:
+
+let
+  arch = with stdenv.hostPlatform;
+    if isAarch64 then "arm"
+    else if isx86_64 then "x86_64"
+    else throw "no seccomp policy files available for host platform";
+
+  crosvmSrc = fetchFromGitiles
+    upstreamInfo.components."chromiumos/platform/crosvm";
+
+  adhdSrc = fetchFromGitiles
+    upstreamInfo.components."chromiumos/third_party/adhd";
+in
+
+  rustPlatform.buildRustPackage rec {
+    pname = "crosvm";
+    inherit (upstreamInfo) version;
+
+    unpackPhase = ''
+      runHook preUnpack
+
+      mkdir -p chromiumos/platform chromiumos/third_party
+
+      pushd chromiumos/platform
+      unpackFile ${crosvmSrc}
+      popd
+
+      pushd chromiumos/third_party
+      unpackFile ${adhdSrc}
+      popd
+
+      chmod -R u+w -- "$sourceRoot"
+
+      runHook postUnpack
+    '';
+
+    sourceRoot = "chromiumos/platform/crosvm";
+
+    patches = [
+      ./default-seccomp-policy-dir.diff
+    ];
+
+    cargoSha256 = "0lhivwvdihslwp81i3sa5q88p5hr83bzkvklrcgf6x73arwk8kdz";
+
+    nativeBuildInputs = [ pkgconfig ];
+
+    buildInputs = [ dtc libcap libusb1 minijail ];
+
+    postPatch = ''
+      sed -i "s|/usr/share/policy/crosvm/|$out/share/policy/|g" \
+             seccomp/*/*.policy
+    '';
+
+    preBuild = ''
+      export DEFAULT_SECCOMP_POLICY_DIR=$out/share/policy
+    '';
+
+    postInstall = ''
+      mkdir -p $out/share/policy/
+      cp seccomp/${arch}/* $out/share/policy/
+    '';
+
+    CROSVM_CARGO_TEST_KERNEL_BINARY =
+      lib.optionalString (stdenv.buildPlatform == stdenv.hostPlatform)
+        "${linux}/${stdenv.hostPlatform.platform.kernelTarget}";
+
+    passthru = {
+      inherit adhdSrc;
+      src = crosvmSrc;
+      updateScript = ../update.py;
+    };
+
+    meta = with lib; {
+      description = "A secure virtual machine monitor for KVM";
+      homepage = "https://chromium.googlesource.com/chromiumos/platform/crosvm/";
+      maintainers = with maintainers; [ qyliss ];
+      license = licenses.bsd3;
+      platforms = [ "aarch64-linux" "x86_64-linux" ];
+    };
+  }
diff --git a/pkgs/os-specific/linux/chromium-os/dbus-properties/default.nix b/pkgs/os-specific/linux/chromium-os/dbus-properties/default.nix
new file mode 100644
index 00000000000..e95ef4a9aa8
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/dbus-properties/default.nix
@@ -0,0 +1,9 @@
+{ runCommand, chromiumos-overlay }:
+
+runCommand "dbus-properties" {
+  passthru.updateScript = ../update.py;
+} ''
+  mkdir -p $out/share/dbus-1/interfaces
+  cp ${chromiumos-overlay}/sys-apps/dbus/files/org.freedesktop.DBus.Properties.xml \
+      $out/share/dbus-1/interfaces
+''
diff --git a/pkgs/os-specific/linux/chromium-os/default.nix b/pkgs/os-specific/linux/chromium-os/default.nix
new file mode 100644
index 00000000000..1bed1ff7b46
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/default.nix
@@ -0,0 +1,63 @@
+{ lib, newScope, fetchFromGitiles, symlinkJoin
+, libqmi, linux_5_4, makeLinuxHeaders, modemmanager
+}:
+
+let
+  self = with self; {
+    callPackage = newScope self;
+
+    upstreamInfo = lib.importJSON ./upstream-info.json;
+
+    chromiumos-overlay = (fetchFromGitiles
+      upstreamInfo.components."chromiumos/overlays/chromiumos-overlay") // {
+        passthru.updateScript = ./update.py;
+      };
+
+    common-mk = callPackage ./common-mk { };
+
+    crosvm = callPackage ./crosvm { };
+
+    dbus-properties = callPackage ./dbus-properties { };
+
+    dbus-interfaces = symlinkJoin {
+      name = "dbus-interfaces";
+      paths = [ dbus-properties self.modemmanager modemmanager-next ];
+      passthru.updateScript = ./update.py;
+    };
+
+    libqmi = callPackage ./libqmi {
+      inherit libqmi;
+    };
+
+    linux_5_4 = callPackage ../kernel/linux-cros.nix {
+      inherit (linux_5_4) kernelPatches;
+    };
+
+    linux = self.linux_5_4;
+
+    linuxHeaders = (makeLinuxHeaders {
+      inherit (linux) version src;
+    });
+
+    minigbm = callPackage ./minigbm { };
+
+    modemmanager = callPackage ./modem-manager {
+      inherit modemmanager;
+    };
+
+    modemmanager-next = callPackage ./modem-manager/next.nix {
+      inherit modemmanager;
+    };
+
+    modp_b64 = callPackage ./modp_b64 { };
+
+    protofiles = callPackage ./protofiles { };
+
+    sommelier = callPackage ./sommelier { };
+
+    vm_protos = callPackage ./vm_protos { };
+  };
+
+in self // (with self; {
+  inherit (upstreamInfo) version;
+})
diff --git a/pkgs/os-specific/linux/chromium-os/libqmi/default.nix b/pkgs/os-specific/linux/chromium-os/libqmi/default.nix
new file mode 100644
index 00000000000..ac444848b81
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/libqmi/default.nix
@@ -0,0 +1,26 @@
+{ libqmi, lib, fetchFromGitiles, upstreamInfo
+, autoreconfHook, autoconf-archive, gtk-doc, docbook-xsl-nons
+}:
+
+libqmi.overrideAttrs (
+  { configureFlags ? [], nativeBuildInputs ? [], passthru ? {}, meta ? {}, ... }:
+  {
+    pname = "libqmi-unstable";
+    version = "2019-12-16";
+
+    src = fetchFromGitiles upstreamInfo.components."chromiumos/third_party/libqmi";
+
+    nativeBuildInputs = nativeBuildInputs ++
+      [ autoreconfHook autoconf-archive gtk-doc docbook-xsl-nons ];
+
+    configureFlags = configureFlags ++ [ "--enable-gtk-doc" ];
+
+    passthru = passthru // {
+      updateScript = ../update.py;
+    };
+
+    meta = with lib; meta // {
+      maintainers = with maintainers; [ qyliss ];
+    };
+  }
+)
diff --git a/pkgs/os-specific/linux/chromium-os/modem-manager/default.nix b/pkgs/os-specific/linux/chromium-os/modem-manager/default.nix
new file mode 100644
index 00000000000..c6a5a44b67e
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/modem-manager/default.nix
@@ -0,0 +1,31 @@
+{ modemmanager, lib, fetchFromGitiles
+, autoreconfHook, libtool, intltool, libxslt, dbus_glib, chromiumos-overlay
+}:
+
+modemmanager.overrideAttrs (
+  { pname, nativeBuildInputs ? [], buildInputs ? [], postInstall ? "", meta ? {}
+  , ... }:
+  {
+    pname = "${pname}-chromiumos-unstable";
+    version = "2012-04-10";
+
+    src = fetchFromGitiles {
+      url = "https://chromium.googlesource.com/chromiumos/third_party/modemmanager";
+      rev = "657324d1abfd446b0319e4c51bd30cf4967eccf4";
+      sha256 = "12wlak8zx914zix4vv5a8sl0nyi58v7593h4gjchgv3i8ysgj9ah";
+    };
+
+    nativeBuildInputs = nativeBuildInputs ++ [ autoreconfHook libtool intltool libxslt ];
+    buildInputs = buildInputs ++ [ dbus_glib ];
+
+    preAutoreconf = ''
+      intltoolize
+    '';
+
+    NIX_CFLAGS_COMPILE = [ "-Wno-error" ];
+
+    meta = with lib; meta // {
+      maintainers = with maintainers; [ qyliss ];
+    };
+  }
+)
diff --git a/pkgs/os-specific/linux/chromium-os/modem-manager/next.nix b/pkgs/os-specific/linux/chromium-os/modem-manager/next.nix
new file mode 100644
index 00000000000..a074e82ff4b
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/modem-manager/next.nix
@@ -0,0 +1,24 @@
+{ modemmanager, lib, fetchFromGitiles, upstreamInfo, autoreconfHook
+, libqmi, libxslt
+}:
+
+modemmanager.overrideAttrs (
+  { pname, nativeBuildInputs ? [], passthru ? {}, meta ? {}, ... }:
+  {
+    pname = "${pname}-chromiumos-next-unstable";
+    version = "2019-10-17";
+
+    src = fetchFromGitiles
+      upstreamInfo.components."chromiumos/third_party/modemmanager-next";
+
+    nativeBuildInputs = nativeBuildInputs ++ [ autoreconfHook libqmi libxslt ];
+
+    passthru = passthru // {
+      updateScript = ../update.py;
+    };
+
+    meta = with lib; meta // {
+      maintainers = with maintainers; [ qyliss ];
+    };
+  }
+)
diff --git a/pkgs/os-specific/linux/chromium-os/modp_b64/default.nix b/pkgs/os-specific/linux/chromium-os/modp_b64/default.nix
new file mode 100644
index 00000000000..50d91479193
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/modp_b64/default.nix
@@ -0,0 +1,23 @@
+{ common-mk, lib, fetchFromGitiles, upstreamInfo }:
+
+common-mk {
+  platformSubdir = "modp_b64";
+
+  src = fetchFromGitiles upstreamInfo.components."aosp/platform/external/modp_b64";
+
+  installPhase = ''
+    mkdir -p $out/lib
+    install -m 0644 libmodp_b64.a $out/lib
+
+    mkdir $out/include
+    cp -r ../../modp_b64/modp_b64 $out/include
+  '';
+
+  meta = with lib; {
+    description = "High performance base64 encoder/decoder";
+    homepage = "https://github.com/client9/stringencoders";
+    license = licenses.bsd3;
+    maintainers = with maintainers; [ qyliss ];
+    platform = platforms.all;
+  };
+}
diff --git a/pkgs/os-specific/linux/chromium-os/protofiles/default.nix b/pkgs/os-specific/linux/chromium-os/protofiles/default.nix
new file mode 100644
index 00000000000..de8ecbb6963
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/protofiles/default.nix
@@ -0,0 +1,34 @@
+{ stdenv, lib, fetchFromGitiles, chromiumos-overlay, python2 }:
+
+stdenv.mkDerivation rec {
+  pname = "protofiles";
+  version = "0.0.36";
+
+  src = fetchFromGitiles {
+    url = "https://chromium.googlesource.com/chromium/src/components/policy";
+    rev = "72e354e16600a8999c85528147dcf762f31a4b78";
+    sha256 = "11v7n8d0ma426ba3i6q82k0vj0m5l1hx49waffivplpn0c92bm94";
+  };
+
+  buildInputs = [ python2 ];
+
+  installPhase = ''
+    mkdir -p $out/include/proto $out/share/protofiles \
+        $out/share/policy_resources $out/share/policy_tools
+
+    install -m 0644 proto/*.proto $out/include/proto
+    ln -s $out/include/proto/*.proto $out/share/protofiles
+    install -m 0644 resources/policy_templates.json $out/share/policy_resources
+    install -m 0644 ${chromiumos-overlay}/chromeos-base/protofiles/files/VERSION \
+      $out/share/policy_resources
+
+    install tools/generate_policy_source.py $out/share/policy_tools
+  '';
+
+  meta = with lib; {
+    inherit (src.meta) homepage;
+    license = licenses.bsd3;
+    maintainers = with maintainers; [ qyliss ];
+    platform = platforms.all;
+  };
+}
diff --git a/pkgs/os-specific/linux/chromium-os/sommelier/0004-sommelier-don-t-leak-source-absolute-paths.patch b/pkgs/os-specific/linux/chromium-os/sommelier/0004-sommelier-don-t-leak-source-absolute-paths.patch
new file mode 100644
index 00000000000..756584365c7
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/sommelier/0004-sommelier-don-t-leak-source-absolute-paths.patch
@@ -0,0 +1,25 @@
+From 1fa4de5b2228c40b25fd6333a74ae7535d73bcce Mon Sep 17 00:00:00 2001
+From: Alyssa Ross <hi@alyssa.is>
+Date: Sun, 1 Dec 2019 17:04:04 +0000
+Subject: [PATCH 4/6] sommelier: don't leak source-absolute paths
+
+---
+ vm_tools/sommelier/wayland_protocol.gni | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/vm_tools/sommelier/wayland_protocol.gni b/vm_tools/sommelier/wayland_protocol.gni
+index 4f18a0c10..b1bd5d659 100644
+--- a/vm_tools/sommelier/wayland_protocol.gni
++++ b/vm_tools/sommelier/wayland_protocol.gni
+@@ -44,7 +44,7 @@ template("wayland_protocol_library") {
+         "wayland-scanner",
+         g.subcommand,
+         "{{source}}",
+-        output_file,
++        rebase_path(output_file),
+       ]
+     }
+   }
+-- 
+2.25.1
+
diff --git a/pkgs/os-specific/linux/chromium-os/sommelier/0005-sommelier-use-stable-xdg-shell-protocol.patch b/pkgs/os-specific/linux/chromium-os/sommelier/0005-sommelier-use-stable-xdg-shell-protocol.patch
new file mode 100644
index 00000000000..20994bc1785
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/sommelier/0005-sommelier-use-stable-xdg-shell-protocol.patch
@@ -0,0 +1,1748 @@
+From 5068e64b2fdedca0a4a9f1894335af8587c4c55a Mon Sep 17 00:00:00 2001
+From: Puck Meerburg <puck@puckipedia.com>
+Date: Tue, 3 Dec 2019 18:06:14 +0000
+Subject: [PATCH 5/6] sommelier: use stable xdg-shell protocol
+
+From https://github.com/wayland-project/weston/commit/d8d9f5e6e16c8f6a3c06763d5f56c27dc9a6e52e:
+
+> Some clients like the mpv video player now request the xdg_shell
+> protocol so these will fail if the compositor only provides the
+> xdg_shell_unstable_v6 protocol. Compositors like mir and gnome provide
+> both protocols.
+---
+ vm_tools/sommelier/BUILD.gn                   |   2 +-
+ ...dg-shell-unstable-v6.xml => xdg-shell.xml} | 319 ++++++++++++------
+ vm_tools/sommelier/sommelier-xdg-shell.c      | 233 ++++++-------
+ vm_tools/sommelier/sommelier.c                | 211 ++++++------
+ vm_tools/sommelier/sommelier.h                |  17 +-
+ 5 files changed, 447 insertions(+), 335 deletions(-)
+ rename vm_tools/sommelier/protocol/{xdg-shell-unstable-v6.xml => xdg-shell.xml} (79%)
+
+diff --git a/vm_tools/sommelier/BUILD.gn b/vm_tools/sommelier/BUILD.gn
+index 5027628d2..4330560a1 100644
+--- a/vm_tools/sommelier/BUILD.gn
++++ b/vm_tools/sommelier/BUILD.gn
+@@ -68,7 +68,7 @@ wayland_protocol_library("sommelier-protocol") {
+     "protocol/relative-pointer-unstable-v1.xml",
+     "protocol/text-input-unstable-v1.xml",
+     "protocol/viewporter.xml",
+-    "protocol/xdg-shell-unstable-v6.xml",
++    "protocol/xdg-shell.xml",
+   ]
+ }
+ 
+diff --git a/vm_tools/sommelier/protocol/xdg-shell-unstable-v6.xml b/vm_tools/sommelier/protocol/xdg-shell.xml
+similarity index 79%
+rename from vm_tools/sommelier/protocol/xdg-shell-unstable-v6.xml
+rename to vm_tools/sommelier/protocol/xdg-shell.xml
+index 1c0f92452..3a87a9ed6 100644
+--- a/vm_tools/sommelier/protocol/xdg-shell-unstable-v6.xml
++++ b/vm_tools/sommelier/protocol/xdg-shell.xml
+@@ -1,11 +1,13 @@
+ <?xml version="1.0" encoding="UTF-8"?>
+-<protocol name="xdg_shell_unstable_v6">
++<protocol name="xdg_shell">
+ 
+   <copyright>
+     Copyright © 2008-2013 Kristian Høgsberg
+     Copyright © 2013      Rafael Antognolli
+     Copyright © 2013      Jasper St. Pierre
+     Copyright © 2010-2013 Intel Corporation
++    Copyright © 2015-2017 Samsung Electronics Co., Ltd
++    Copyright © 2015-2017 Red Hat Inc.
+ 
+     Permission is hereby granted, free of charge, to any person obtaining a
+     copy of this software and associated documentation files (the "Software"),
+@@ -27,18 +29,19 @@
+     DEALINGS IN THE SOFTWARE.
+   </copyright>
+ 
+-  <interface name="zxdg_shell_v6" version="1">
++  <interface name="xdg_wm_base" version="2">
+     <description summary="create desktop-style surfaces">
+-      xdg_shell allows clients to turn a wl_surface into a "real window"
+-      which can be dragged, resized, stacked, and moved around by the
+-      user. Everything about this interface is suited towards traditional
+-      desktop environments.
++      The xdg_wm_base interface is exposed as a global object enabling clients
++      to turn their wl_surfaces into windows in a desktop environment. It
++      defines the basic functionality needed for clients and the compositor to
++      create windows that can be dragged, resized, maximized, etc, as well as
++      creating transient windows such as popup menus.
+     </description>
+ 
+     <enum name="error">
+       <entry name="role" value="0" summary="given wl_surface has another role"/>
+       <entry name="defunct_surfaces" value="1"
+-	     summary="xdg_shell was destroyed before children"/>
++	     summary="xdg_wm_base was destroyed before children"/>
+       <entry name="not_the_topmost_popup" value="2"
+ 	     summary="the client tried to map or destroy a non-topmost popup"/>
+       <entry name="invalid_popup_parent" value="3"
+@@ -50,11 +53,11 @@
+     </enum>
+ 
+     <request name="destroy" type="destructor">
+-      <description summary="destroy xdg_shell">
+-	Destroy this xdg_shell object.
++      <description summary="destroy xdg_wm_base">
++	Destroy this xdg_wm_base object.
+ 
+-	Destroying a bound xdg_shell object while there are surfaces
+-	still alive created by this xdg_shell object instance is illegal
++	Destroying a bound xdg_wm_base object while there are surfaces
++	still alive created by this xdg_wm_base object instance is illegal
+ 	and will result in a protocol error.
+       </description>
+     </request>
+@@ -65,7 +68,7 @@
+ 	surfaces relative to some parent surface. See the interface description
+ 	and xdg_surface.get_popup for details.
+       </description>
+-      <arg name="id" type="new_id" interface="zxdg_positioner_v6"/>
++      <arg name="id" type="new_id" interface="xdg_positioner"/>
+     </request>
+ 
+     <request name="get_xdg_surface">
+@@ -82,14 +85,14 @@
+ 	See the documentation of xdg_surface for more details about what an
+ 	xdg_surface is and how it is used.
+       </description>
+-      <arg name="id" type="new_id" interface="zxdg_surface_v6"/>
++      <arg name="id" type="new_id" interface="xdg_surface"/>
+       <arg name="surface" type="object" interface="wl_surface"/>
+     </request>
+ 
+     <request name="pong">
+       <description summary="respond to a ping event">
+ 	A client must respond to a ping event with a pong request or
+-	the client may be deemed unresponsive. See xdg_shell.ping.
++	the client may be deemed unresponsive. See xdg_wm_base.ping.
+       </description>
+       <arg name="serial" type="uint" summary="serial of the ping event"/>
+     </request>
+@@ -98,7 +101,7 @@
+       <description summary="check if the client is alive">
+ 	The ping event asks the client if it's still alive. Pass the
+ 	serial specified in the event back to the compositor by sending
+-	a "pong" request back with the specified serial. See xdg_shell.ping.
++	a "pong" request back with the specified serial. See xdg_wm_base.pong.
+ 
+ 	Compositors can use this to determine if the client is still
+ 	alive. It's unspecified what will happen if the client doesn't
+@@ -106,13 +109,13 @@
+ 	try to respond in a reasonable amount of time.
+ 
+ 	A compositor is free to ping in any way it wants, but a client must
+-	always respond to any xdg_shell object it created.
++	always respond to any xdg_wm_base object it created.
+       </description>
+       <arg name="serial" type="uint" summary="pass this to the pong request"/>
+     </event>
+   </interface>
+ 
+-  <interface name="zxdg_positioner_v6" version="1">
++  <interface name="xdg_positioner" version="2">
+     <description summary="child surface positioner">
+       The xdg_positioner provides a collection of rules for the placement of a
+       child surface relative to a parent surface. Rules can be defined to ensure
+@@ -162,13 +165,13 @@
+ 	Specify the anchor rectangle within the parent surface that the child
+ 	surface will be placed relative to. The rectangle is relative to the
+ 	window geometry as defined by xdg_surface.set_window_geometry of the
+-	parent surface. The rectangle must be at least 1x1 large.
++	parent surface.
+ 
+ 	When the xdg_positioner object is used to position a child surface, the
+ 	anchor rectangle may not extend outside the window geometry of the
+ 	positioned child's parent surface.
+ 
+-	If a zero or negative size is set the invalid_input error is raised.
++	If a negative size is set the invalid_input error is raised.
+       </description>
+       <arg name="x" type="int" summary="x position of anchor rectangle"/>
+       <arg name="y" type="int" summary="y position of anchor rectangle"/>
+@@ -176,63 +179,54 @@
+       <arg name="height" type="int" summary="height of anchor rectangle"/>
+     </request>
+ 
+-    <enum name="anchor" bitfield="true">
+-      <entry name="none" value="0"
+-	     summary="the center of the anchor rectangle"/>
+-      <entry name="top" value="1"
+-	     summary="the top edge of the anchor rectangle"/>
+-      <entry name="bottom" value="2"
+-	     summary="the bottom edge of the anchor rectangle"/>
+-      <entry name="left" value="4"
+-	     summary="the left edge of the anchor rectangle"/>
+-      <entry name="right" value="8"
+-	     summary="the right edge of the anchor rectangle"/>
++    <enum name="anchor">
++      <entry name="none" value="0"/>
++      <entry name="top" value="1"/>
++      <entry name="bottom" value="2"/>
++      <entry name="left" value="3"/>
++      <entry name="right" value="4"/>
++      <entry name="top_left" value="5"/>
++      <entry name="bottom_left" value="6"/>
++      <entry name="top_right" value="7"/>
++      <entry name="bottom_right" value="8"/>
+     </enum>
+ 
+     <request name="set_anchor">
+-      <description summary="set anchor rectangle anchor edges">
+-	Defines a set of edges for the anchor rectangle. These are used to
+-	derive an anchor point that the child surface will be positioned
+-	relative to. If two orthogonal edges are specified (e.g. 'top' and
+-	'left'), then the anchor point will be the intersection of the edges
+-	(e.g. the top left position of the rectangle); otherwise, the derived
+-	anchor point will be centered on the specified edge, or in the center of
+-	the anchor rectangle if no edge is specified.
+-
+-	If two parallel anchor edges are specified (e.g. 'left' and 'right'),
+-	the invalid_input error is raised.
++      <description summary="set anchor rectangle anchor">
++	Defines the anchor point for the anchor rectangle. The specified anchor
++	is used derive an anchor point that the child surface will be
++	positioned relative to. If a corner anchor is set (e.g. 'top_left' or
++	'bottom_right'), the anchor point will be at the specified corner;
++	otherwise, the derived anchor point will be centered on the specified
++	edge, or in the center of the anchor rectangle if no edge is specified.
+       </description>
+       <arg name="anchor" type="uint" enum="anchor"
+-	   summary="bit mask of anchor edges"/>
++	   summary="anchor"/>
+     </request>
+ 
+-    <enum name="gravity" bitfield="true">
+-      <entry name="none" value="0"
+-	     summary="center over the anchor edge"/>
+-      <entry name="top" value="1"
+-	     summary="position above the anchor edge"/>
+-      <entry name="bottom" value="2"
+-	     summary="position below the anchor edge"/>
+-      <entry name="left" value="4"
+-	     summary="position to the left of the anchor edge"/>
+-      <entry name="right" value="8"
+-	     summary="position to the right of the anchor edge"/>
++    <enum name="gravity">
++      <entry name="none" value="0"/>
++      <entry name="top" value="1"/>
++      <entry name="bottom" value="2"/>
++      <entry name="left" value="3"/>
++      <entry name="right" value="4"/>
++      <entry name="top_left" value="5"/>
++      <entry name="bottom_left" value="6"/>
++      <entry name="top_right" value="7"/>
++      <entry name="bottom_right" value="8"/>
+     </enum>
+ 
+     <request name="set_gravity">
+       <description summary="set child surface gravity">
+ 	Defines in what direction a surface should be positioned, relative to
+-	the anchor point of the parent surface. If two orthogonal gravities are
+-	specified (e.g. 'bottom' and 'right'), then the child surface will be
+-	placed in the specified direction; otherwise, the child surface will be
+-	centered over the anchor point on any axis that had no gravity
+-	specified.
+-
+-	If two parallel gravities are specified (e.g. 'left' and 'right'), the
+-	invalid_input error is raised.
++	the anchor point of the parent surface. If a corner gravity is
++	specified (e.g. 'bottom_right' or 'top_left'), then the child surface
++	will be placed towards the specified gravity; otherwise, the child
++	surface will be centered over the anchor point on any axis that had no
++	gravity specified.
+       </description>
+       <arg name="gravity" type="uint" enum="gravity"
+-	   summary="bit mask of gravity directions"/>
++	   summary="gravity direction"/>
+     </request>
+ 
+     <enum name="constraint_adjustment" bitfield="true">
+@@ -252,7 +246,7 @@
+       <entry name="none" value="0">
+ 	<description summary="don't move the child surface when constrained">
+ 	  Don't alter the surface position even if it is constrained on some
+-	  axis, for example partially outside the edge of a monitor.
++	  axis, for example partially outside the edge of an output.
+ 	</description>
+       </entry>
+       <entry name="slide_x" value="1">
+@@ -304,6 +298,10 @@
+ 	  surface is constrained, the gravity is 'bottom' and the anchor is
+ 	  'bottom', change the gravity to 'top' and the anchor to 'top'.
+ 
++	  The adjusted position is calculated given the original anchor
++	  rectangle and offset, but with the new flipped anchor and gravity
++	  values.
++
+ 	  If the adjusted position also ends up being constrained, the resulting
+ 	  position of the flip_y adjustment will be the one before the
+ 	  adjustment.
+@@ -361,7 +359,7 @@
+     </request>
+   </interface>
+ 
+-  <interface name="zxdg_surface_v6" version="1">
++  <interface name="xdg_surface" version="2">
+     <description summary="desktop user interface surface base interface">
+       An interface that may be implemented by a wl_surface, for
+       implementations that provide a desktop-style user interface.
+@@ -388,11 +386,20 @@
+       manipulate a buffer prior to the first xdg_surface.configure call must
+       also be treated as errors.
+ 
+-      For a surface to be mapped by the compositor, the following conditions
+-      must be met: (1) the client has assigned a xdg_surface based role to the
+-      surface, (2) the client has set and committed the xdg_surface state and
+-      the role dependent state to the surface and (3) the client has committed a
+-      buffer to the surface.
++      Mapping an xdg_surface-based role surface is defined as making it
++      possible for the surface to be shown by the compositor. Note that
++      a mapped surface is not guaranteed to be visible once it is mapped.
++
++      For an xdg_surface to be mapped by the compositor, the following
++      conditions must be met:
++      (1) the client has assigned an xdg_surface-based role to the surface
++      (2) the client has set and committed the xdg_surface state and the
++	  role-dependent state to the surface
++      (3) the client has committed a buffer to the surface
++
++      A newly-unmapped surface is considered to have met condition (1) out
++      of the 3 required conditions for mapping a surface if its role surface
++      has not been destroyed.
+     </description>
+ 
+     <enum name="error">
+@@ -416,20 +423,23 @@
+ 	See the documentation of xdg_toplevel for more details about what an
+ 	xdg_toplevel is and how it is used.
+       </description>
+-      <arg name="id" type="new_id" interface="zxdg_toplevel_v6"/>
++      <arg name="id" type="new_id" interface="xdg_toplevel"/>
+     </request>
+ 
+     <request name="get_popup">
+       <description summary="assign the xdg_popup surface role">
+-	This creates an xdg_popup object for the given xdg_surface and gives the
+-	associated wl_surface the xdg_popup role.
++	This creates an xdg_popup object for the given xdg_surface and gives
++	the associated wl_surface the xdg_popup role.
++
++	If null is passed as a parent, a parent surface must be specified using
++	some other protocol, before committing the initial state.
+ 
+ 	See the documentation of xdg_popup for more details about what an
+ 	xdg_popup is and how it is used.
+       </description>
+-      <arg name="id" type="new_id" interface="zxdg_popup_v6"/>
+-      <arg name="parent" type="object" interface="zxdg_surface_v6"/>
+-      <arg name="positioner" type="object" interface="zxdg_positioner_v6"/>
++      <arg name="id" type="new_id" interface="xdg_popup"/>
++      <arg name="parent" type="object" interface="xdg_surface" allow-null="true"/>
++      <arg name="positioner" type="object" interface="xdg_positioner"/>
+     </request>
+ 
+     <request name="set_window_geometry">
+@@ -442,6 +452,11 @@
+ 	The window geometry is double buffered, and will be applied at the
+ 	time wl_surface.commit of the corresponding wl_surface is called.
+ 
++	When maintaining a position, the compositor should treat the (x, y)
++	coordinate of the window geometry as the top left corner of the window.
++	A client changing the (x, y) window geometry coordinate should in
++	general not alter the position of the window.
++
+ 	Once the window geometry of the surface is set, it is not possible to
+ 	unset it, and it will remain the same until set_window_geometry is
+ 	called again, even if a new subsurface or buffer is attached.
+@@ -513,34 +528,50 @@
+     </event>
+   </interface>
+ 
+-  <interface name="zxdg_toplevel_v6" version="1">
++  <interface name="xdg_toplevel" version="2">
+     <description summary="toplevel surface">
+       This interface defines an xdg_surface role which allows a surface to,
+       among other things, set window-like properties such as maximize,
+       fullscreen, and minimize, set application-specific metadata like title and
+       id, and well as trigger user interactive operations such as interactive
+       resize and move.
++
++      Unmapping an xdg_toplevel means that the surface cannot be shown
++      by the compositor until it is explicitly mapped again.
++      All active operations (e.g., move, resize) are canceled and all
++      attributes (e.g. title, state, stacking, ...) are discarded for
++      an xdg_toplevel surface when it is unmapped.
++
++      Attaching a null buffer to a toplevel unmaps the surface.
+     </description>
+ 
+     <request name="destroy" type="destructor">
+       <description summary="destroy the xdg_toplevel">
+-	Unmap and destroy the window. The window will be effectively
+-	hidden from the user's point of view, and all state like
+-	maximization, fullscreen, and so on, will be lost.
++	This request destroys the role surface and unmaps the surface;
++	see "Unmapping" behavior in interface section for details.
+       </description>
+     </request>
+ 
+     <request name="set_parent">
+       <description summary="set the parent of this surface">
+-	Set the "parent" of this surface. This window should be stacked
+-	above a parent. The parent surface must be mapped as long as this
+-	surface is mapped.
++	Set the "parent" of this surface. This surface should be stacked
++	above the parent surface and all other ancestor surfaces.
+ 
+ 	Parent windows should be set on dialogs, toolboxes, or other
+ 	"auxiliary" surfaces, so that the parent is raised when the dialog
+ 	is raised.
++
++	Setting a null parent for a child window removes any parent-child
++	relationship for the child. Setting a null parent for a window which
++	currently has no parent is a no-op.
++
++	If the parent is unmapped then its children are managed as
++	though the parent of the now-unmapped parent has become the
++	parent of this surface. If no parent exists for the now-unmapped
++	parent then the children are managed as though they have no
++	parent surface.
+       </description>
+-      <arg name="parent" type="object" interface="zxdg_toplevel_v6" allow-null="true"/>
++      <arg name="parent" type="object" interface="xdg_toplevel" allow-null="true"/>
+     </request>
+ 
+     <request name="set_title">
+@@ -573,6 +604,9 @@
+ 	For example, "org.freedesktop.FooViewer" where the .desktop file is
+ 	"org.freedesktop.FooViewer.desktop".
+ 
++	Like other properties, a set_app_id request can be sent after the
++	xdg_toplevel has been mapped to update the property.
++
+ 	See the desktop-entry specification [0] for more details on
+ 	application identifiers and how they relate to well-known D-Bus
+ 	names and .desktop files.
+@@ -693,12 +727,18 @@
+ 	<description summary="the surface is maximized">
+ 	  The surface is maximized. The window geometry specified in the configure
+ 	  event must be obeyed by the client.
++
++	  The client should draw without shadow or other
++	  decoration outside of the window geometry.
+ 	</description>
+       </entry>
+       <entry name="fullscreen" value="2" summary="the surface is fullscreen">
+ 	<description summary="the surface is fullscreen">
+-	  The surface is fullscreen. The window geometry specified in the configure
+-	  event must be obeyed by the client.
++	  The surface is fullscreen. The window geometry specified in the
++	  configure event is a maximum; the client cannot resize beyond it. For
++	  a surface to cover the whole fullscreened area, the geometry
++	  dimensions must be obeyed by the client. For more details, see
++	  xdg_toplevel.set_fullscreen.
+ 	</description>
+       </entry>
+       <entry name="resizing" value="3" summary="the surface is being resized">
+@@ -716,6 +756,30 @@
+ 	  keyboard or pointer focus.
+ 	</description>
+       </entry>
++      <entry name="tiled_left" value="5" since="2">
++	<description summary="the surface is tiled">
++	  The window is currently in a tiled layout and the left edge is
++	  considered to be adjacent to another part of the tiling grid.
++	</description>
++      </entry>
++      <entry name="tiled_right" value="6" since="2">
++	<description summary="the surface is tiled">
++	  The window is currently in a tiled layout and the right edge is
++	  considered to be adjacent to another part of the tiling grid.
++	</description>
++      </entry>
++      <entry name="tiled_top" value="7" since="2">
++	<description summary="the surface is tiled">
++	  The window is currently in a tiled layout and the top edge is
++	  considered to be adjacent to another part of the tiling grid.
++	</description>
++      </entry>
++      <entry name="tiled_bottom" value="8" since="2">
++	<description summary="the surface is tiled">
++	  The window is currently in a tiled layout and the bottom edge is
++	  considered to be adjacent to another part of the tiling grid.
++	</description>
++      </entry>
+     </enum>
+ 
+     <request name="set_max_size">
+@@ -805,12 +869,11 @@
+ 	Maximize the surface.
+ 
+ 	After requesting that the surface should be maximized, the compositor
+-	will respond by emitting a configure event with the "maximized" state
+-	and the required window geometry. The client should then update its
+-	content, drawing it in a maximized state, i.e. without shadow or other
+-	decoration outside of the window geometry. The client must also
+-	acknowledge the configure when committing the new content (see
+-	ack_configure).
++	will respond by emitting a configure event. Whether this configure
++	actually sets the window maximized is subject to compositor policies.
++	The client must then update its content, drawing in the configured
++	state. The client must also acknowledge the configure when committing
++	the new content (see ack_configure).
+ 
+ 	It is up to the compositor to decide how and where to maximize the
+ 	surface, for example which output and what region of the screen should
+@@ -818,6 +881,10 @@
+ 
+ 	If the surface was already maximized, the compositor will still emit
+ 	a configure event with the "maximized" state.
++
++	If the surface is in a fullscreen state, this request has no direct
++	effect. It may alter the state the surface is returned to when
++	unmaximized unless overridden by the compositor.
+       </description>
+     </request>
+ 
+@@ -826,13 +893,13 @@
+ 	Unmaximize the surface.
+ 
+ 	After requesting that the surface should be unmaximized, the compositor
+-	will respond by emitting a configure event without the "maximized"
+-	state. If available, the compositor will include the window geometry
+-	dimensions the window had prior to being maximized in the configure
+-	request. The client must then update its content, drawing it in a
+-	regular state, i.e. potentially with shadow, etc. The client must also
+-	acknowledge the configure when committing the new content (see
+-	ack_configure).
++	will respond by emitting a configure event. Whether this actually
++	un-maximizes the window is subject to compositor policies.
++	If available and applicable, the compositor will include the window
++	geometry dimensions the window had prior to being maximized in the
++	configure event. The client must then update its content, drawing it in
++	the configured state. The client must also acknowledge the configure
++	when committing the new content (see ack_configure).
+ 
+ 	It is up to the compositor to position the surface after it was
+ 	unmaximized; usually the position the surface had before maximizing, if
+@@ -840,24 +907,63 @@
+ 
+ 	If the surface was already not maximized, the compositor will still
+ 	emit a configure event without the "maximized" state.
++
++	If the surface is in a fullscreen state, this request has no direct
++	effect. It may alter the state the surface is returned to when
++	unmaximized unless overridden by the compositor.
+       </description>
+     </request>
+ 
+     <request name="set_fullscreen">
+-      <description summary="set the window as fullscreen on a monitor">
++      <description summary="set the window as fullscreen on an output">
+ 	Make the surface fullscreen.
+ 
+-	You can specify an output that you would prefer to be fullscreen.
+-	If this value is NULL, it's up to the compositor to choose which
+-	display will be used to map this surface.
++	After requesting that the surface should be fullscreened, the
++	compositor will respond by emitting a configure event. Whether the
++	client is actually put into a fullscreen state is subject to compositor
++	policies. The client must also acknowledge the configure when
++	committing the new content (see ack_configure).
++
++	The output passed by the request indicates the client's preference as
++	to which display it should be set fullscreen on. If this value is NULL,
++	it's up to the compositor to choose which display will be used to map
++	this surface.
+ 
+ 	If the surface doesn't cover the whole output, the compositor will
+ 	position the surface in the center of the output and compensate with
+-	black borders filling the rest of the output.
++	with border fill covering the rest of the output. The content of the
++	border fill is undefined, but should be assumed to be in some way that
++	attempts to blend into the surrounding area (e.g. solid black).
++
++	If the fullscreened surface is not opaque, the compositor must make
++	sure that other screen content not part of the same surface tree (made
++	up of subsurfaces, popups or similarly coupled surfaces) are not
++	visible below the fullscreened surface.
+       </description>
+       <arg name="output" type="object" interface="wl_output" allow-null="true"/>
+     </request>
+-    <request name="unset_fullscreen" />
++
++    <request name="unset_fullscreen">
++      <description summary="unset the window as fullscreen">
++	Make the surface no longer fullscreen.
++
++	After requesting that the surface should be unfullscreened, the
++	compositor will respond by emitting a configure event.
++	Whether this actually removes the fullscreen state of the client is
++	subject to compositor policies.
++
++	Making a surface unfullscreen sets states for the surface based on the following:
++	* the state(s) it may have had before becoming fullscreen
++	* any state(s) decided by the compositor
++	* any state(s) requested by the client while the surface was fullscreen
++
++	The compositor may include the previous window geometry dimensions in
++	the configure event, if applicable.
++
++	The client must also acknowledge the configure when committing the new
++	content (see ack_configure).
++      </description>
++    </request>
+ 
+     <request name="set_minimized">
+       <description summary="set the window as minimized">
+@@ -913,7 +1019,7 @@
+     </event>
+   </interface>
+ 
+-  <interface name="zxdg_popup_v6" version="1">
++  <interface name="xdg_popup" version="2">
+     <description summary="short-lived, popup surfaces for menus">
+       A popup surface is a short-lived, temporary surface. It can be used to
+       implement for example menus, popovers, tooltips and other similar user
+@@ -931,9 +1037,6 @@
+       surface of their own is clicked should dismiss the popup using the destroy
+       request.
+ 
+-      The parent surface must have either the xdg_toplevel or xdg_popup surface
+-      role.
+-
+       A newly created xdg_popup will be stacked on top of all previously created
+       xdg_popup surfaces associated with the same xdg_toplevel.
+ 
+diff --git a/vm_tools/sommelier/sommelier-xdg-shell.c b/vm_tools/sommelier/sommelier-xdg-shell.c
+index ecd0fc647..a3ba0d6e1 100644
+--- a/vm_tools/sommelier/sommelier-xdg-shell.c
++++ b/vm_tools/sommelier/sommelier-xdg-shell.c
+@@ -7,37 +7,37 @@
+ #include <assert.h>
+ #include <stdlib.h>
+ 
+-#include "xdg-shell-unstable-v6-client-protocol.h"
+-#include "xdg-shell-unstable-v6-server-protocol.h"
++#include "xdg-shell-client-protocol.h"
++#include "xdg-shell-server-protocol.h"
+ 
+-struct sl_host_xdg_shell {
++struct sl_host_xdg_wm_base {
+   struct sl_context* ctx;
+   struct wl_resource* resource;
+-  struct zxdg_shell_v6* proxy;
++  struct xdg_wm_base* proxy;
+ };
+ 
+ struct sl_host_xdg_surface {
+   struct sl_context* ctx;
+   struct wl_resource* resource;
+-  struct zxdg_surface_v6* proxy;
++  struct xdg_surface* proxy;
+ };
+ 
+ struct sl_host_xdg_toplevel {
+   struct sl_context* ctx;
+   struct wl_resource* resource;
+-  struct zxdg_toplevel_v6* proxy;
++  struct xdg_toplevel* proxy;
+ };
+ 
+ struct sl_host_xdg_popup {
+   struct sl_context* ctx;
+   struct wl_resource* resource;
+-  struct zxdg_popup_v6* proxy;
++  struct xdg_popup* proxy;
+ };
+ 
+ struct sl_host_xdg_positioner {
+   struct sl_context* ctx;
+   struct wl_resource* resource;
+-  struct zxdg_positioner_v6* proxy;
++  struct xdg_positioner* proxy;
+ };
+ 
+ static void sl_xdg_positioner_destroy(struct wl_client* client,
+@@ -52,7 +52,7 @@ static void sl_xdg_positioner_set_size(struct wl_client* client,
+   struct sl_host_xdg_positioner* host = wl_resource_get_user_data(resource);
+   double scale = host->ctx->scale;
+ 
+-  zxdg_positioner_v6_set_size(host->proxy, width / scale, height / scale);
++  xdg_positioner_set_size(host->proxy, width / scale, height / scale);
+ }
+ 
+ static void sl_xdg_positioner_set_anchor_rect(struct wl_client* client,
+@@ -70,7 +70,7 @@ static void sl_xdg_positioner_set_anchor_rect(struct wl_client* client,
+   x2 = (x + width) / scale;
+   y2 = (y + height) / scale;
+ 
+-  zxdg_positioner_v6_set_anchor_rect(host->proxy, x1, y1, x2 - x1, y2 - y1);
++  xdg_positioner_set_anchor_rect(host->proxy, x1, y1, x2 - x1, y2 - y1);
+ }
+ 
+ static void sl_xdg_positioner_set_anchor(struct wl_client* client,
+@@ -78,7 +78,7 @@ static void sl_xdg_positioner_set_anchor(struct wl_client* client,
+                                          uint32_t anchor) {
+   struct sl_host_xdg_positioner* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_positioner_v6_set_anchor(host->proxy, anchor);
++  xdg_positioner_set_anchor(host->proxy, anchor);
+ }
+ 
+ static void sl_xdg_positioner_set_gravity(struct wl_client* client,
+@@ -86,7 +86,7 @@ static void sl_xdg_positioner_set_gravity(struct wl_client* client,
+                                           uint32_t gravity) {
+   struct sl_host_xdg_positioner* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_positioner_v6_set_gravity(host->proxy, gravity);
++  xdg_positioner_set_gravity(host->proxy, gravity);
+ }
+ 
+ static void sl_xdg_positioner_set_constraint_adjustment(
+@@ -95,8 +95,8 @@ static void sl_xdg_positioner_set_constraint_adjustment(
+     uint32_t constraint_adjustment) {
+   struct sl_host_xdg_positioner* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_positioner_v6_set_constraint_adjustment(host->proxy,
+-                                               constraint_adjustment);
++  xdg_positioner_set_constraint_adjustment(host->proxy,
++                                           constraint_adjustment);
+ }
+ 
+ static void sl_xdg_positioner_set_offset(struct wl_client* client,
+@@ -106,10 +106,10 @@ static void sl_xdg_positioner_set_offset(struct wl_client* client,
+   struct sl_host_xdg_positioner* host = wl_resource_get_user_data(resource);
+   double scale = host->ctx->scale;
+ 
+-  zxdg_positioner_v6_set_offset(host->proxy, x / scale, y / scale);
++  xdg_positioner_set_offset(host->proxy, x / scale, y / scale);
+ }
+ 
+-static const struct zxdg_positioner_v6_interface
++static const struct xdg_positioner_interface
+     sl_xdg_positioner_implementation = {
+         sl_xdg_positioner_destroy,
+         sl_xdg_positioner_set_size,
+@@ -122,7 +122,7 @@ static const struct zxdg_positioner_v6_interface
+ static void sl_destroy_host_xdg_positioner(struct wl_resource* resource) {
+   struct sl_host_xdg_positioner* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_positioner_v6_destroy(host->proxy);
++  xdg_positioner_destroy(host->proxy);
+   wl_resource_set_user_data(resource, NULL);
+   free(host);
+ }
+@@ -139,19 +139,19 @@ static void sl_xdg_popup_grab(struct wl_client* client,
+   struct sl_host_xdg_popup* host = wl_resource_get_user_data(resource);
+   struct sl_host_seat* host_seat = wl_resource_get_user_data(seat_resource);
+ 
+-  zxdg_popup_v6_grab(host->proxy, host_seat->proxy, serial);
++  xdg_popup_grab(host->proxy, host_seat->proxy, serial);
+ }
+ 
+-static const struct zxdg_popup_v6_interface sl_xdg_popup_implementation = {
++static const struct xdg_popup_interface sl_xdg_popup_implementation = {
+     sl_xdg_popup_destroy, sl_xdg_popup_grab};
+ 
+ static void sl_xdg_popup_configure(void* data,
+-                                   struct zxdg_popup_v6* xdg_popup,
++                                   struct xdg_popup* xdg_popup,
+                                    int32_t x,
+                                    int32_t y,
+                                    int32_t width,
+                                    int32_t height) {
+-  struct sl_host_xdg_popup* host = zxdg_popup_v6_get_user_data(xdg_popup);
++  struct sl_host_xdg_popup* host = xdg_popup_get_user_data(xdg_popup);
+   double scale = host->ctx->scale;
+   int32_t x1, y1, x2, y2;
+ 
+@@ -160,23 +160,23 @@ static void sl_xdg_popup_configure(void* data,
+   x2 = (x + width) * scale;
+   y2 = (y + height) * scale;
+ 
+-  zxdg_popup_v6_send_configure(host->resource, x1, y1, x2 - x1, y2 - y1);
++  xdg_popup_send_configure(host->resource, x1, y1, x2 - x1, y2 - y1);
+ }
+ 
+ static void sl_xdg_popup_popup_done(void* data,
+-                                    struct zxdg_popup_v6* xdg_popup) {
+-  struct sl_host_xdg_popup* host = zxdg_popup_v6_get_user_data(xdg_popup);
++                                    struct xdg_popup* xdg_popup) {
++  struct sl_host_xdg_popup* host = xdg_popup_get_user_data(xdg_popup);
+ 
+-  zxdg_popup_v6_send_popup_done(host->resource);
++  xdg_popup_send_popup_done(host->resource);
+ }
+ 
+-static const struct zxdg_popup_v6_listener sl_xdg_popup_listener = {
++static const struct xdg_popup_listener sl_xdg_popup_listener = {
+     sl_xdg_popup_configure, sl_xdg_popup_popup_done};
+ 
+ static void sl_destroy_host_xdg_popup(struct wl_resource* resource) {
+   struct sl_host_xdg_popup* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_popup_v6_destroy(host->proxy);
++  xdg_popup_destroy(host->proxy);
+   wl_resource_set_user_data(resource, NULL);
+   free(host);
+ }
+@@ -193,8 +193,8 @@ static void sl_xdg_toplevel_set_parent(struct wl_client* client,
+   struct sl_host_xdg_toplevel* host_parent =
+       parent_resource ? wl_resource_get_user_data(parent_resource) : NULL;
+ 
+-  zxdg_toplevel_v6_set_parent(host->proxy,
+-                              host_parent ? host_parent->proxy : NULL);
++  xdg_toplevel_set_parent(host->proxy,
++                          host_parent ? host_parent->proxy : NULL);
+ }
+ 
+ static void sl_xdg_toplevel_set_title(struct wl_client* client,
+@@ -202,7 +202,7 @@ static void sl_xdg_toplevel_set_title(struct wl_client* client,
+                                       const char* title) {
+   struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_toplevel_v6_set_title(host->proxy, title);
++  xdg_toplevel_set_title(host->proxy, title);
+ }
+ 
+ static void sl_xdg_toplevel_set_app_id(struct wl_client* client,
+@@ -210,7 +210,7 @@ static void sl_xdg_toplevel_set_app_id(struct wl_client* client,
+                                        const char* app_id) {
+   struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_toplevel_v6_set_app_id(host->proxy, app_id);
++  xdg_toplevel_set_app_id(host->proxy, app_id);
+ }
+ 
+ static void sl_xdg_toplevel_show_window_menu(struct wl_client* client,
+@@ -223,7 +223,7 @@ static void sl_xdg_toplevel_show_window_menu(struct wl_client* client,
+   struct sl_host_seat* host_seat =
+       seat_resource ? wl_resource_get_user_data(seat_resource) : NULL;
+ 
+-  zxdg_toplevel_v6_show_window_menu(
++  xdg_toplevel_show_window_menu(
+       host->proxy, host_seat ? host_seat->proxy : NULL, serial, x, y);
+ }
+ 
+@@ -235,8 +235,8 @@ static void sl_xdg_toplevel_move(struct wl_client* client,
+   struct sl_host_seat* host_seat =
+       seat_resource ? wl_resource_get_user_data(seat_resource) : NULL;
+ 
+-  zxdg_toplevel_v6_move(host->proxy, host_seat ? host_seat->proxy : NULL,
+-                        serial);
++  xdg_toplevel_move(host->proxy, host_seat ? host_seat->proxy : NULL,
++                    serial);
+ }
+ 
+ static void sl_xdg_toplevel_resize(struct wl_client* client,
+@@ -248,8 +248,8 @@ static void sl_xdg_toplevel_resize(struct wl_client* client,
+   struct sl_host_seat* host_seat =
+       seat_resource ? wl_resource_get_user_data(seat_resource) : NULL;
+ 
+-  zxdg_toplevel_v6_resize(host->proxy, host_seat ? host_seat->proxy : NULL,
+-                          serial, edges);
++  xdg_toplevel_resize(host->proxy, host_seat ? host_seat->proxy : NULL,
++                      serial, edges);
+ }
+ 
+ static void sl_xdg_toplevel_set_max_size(struct wl_client* client,
+@@ -258,7 +258,7 @@ static void sl_xdg_toplevel_set_max_size(struct wl_client* client,
+                                          int32_t height) {
+   struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_toplevel_v6_set_max_size(host->proxy, width, height);
++  xdg_toplevel_set_max_size(host->proxy, width, height);
+ }
+ 
+ static void sl_xdg_toplevel_set_min_size(struct wl_client* client,
+@@ -267,21 +267,21 @@ static void sl_xdg_toplevel_set_min_size(struct wl_client* client,
+                                          int32_t height) {
+   struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_toplevel_v6_set_min_size(host->proxy, width, height);
++  xdg_toplevel_set_min_size(host->proxy, width, height);
+ }
+ 
+ static void sl_xdg_toplevel_set_maximized(struct wl_client* client,
+                                           struct wl_resource* resource) {
+   struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_toplevel_v6_set_maximized(host->proxy);
++  xdg_toplevel_set_maximized(host->proxy);
+ }
+ 
+ static void sl_xdg_toplevel_unset_maximized(struct wl_client* client,
+                                             struct wl_resource* resource) {
+   struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_toplevel_v6_unset_maximized(host->proxy);
++  xdg_toplevel_unset_maximized(host->proxy);
+ }
+ 
+ static void sl_xdg_toplevel_set_fullscreen(
+@@ -292,25 +292,25 @@ static void sl_xdg_toplevel_set_fullscreen(
+   struct sl_host_output* host_output =
+       output_resource ? wl_resource_get_user_data(output_resource) : NULL;
+ 
+-  zxdg_toplevel_v6_set_fullscreen(host->proxy,
+-                                  host_output ? host_output->proxy : NULL);
++  xdg_toplevel_set_fullscreen(host->proxy,
++                              host_output ? host_output->proxy : NULL);
+ }
+ 
+ static void sl_xdg_toplevel_unset_fullscreen(struct wl_client* client,
+                                              struct wl_resource* resource) {
+   struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_toplevel_v6_unset_fullscreen(host->proxy);
++  xdg_toplevel_unset_fullscreen(host->proxy);
+ }
+ 
+ static void sl_xdg_toplevel_set_minimized(struct wl_client* client,
+                                           struct wl_resource* resource) {
+   struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_toplevel_v6_set_minimized(host->proxy);
++  xdg_toplevel_set_minimized(host->proxy);
+ }
+ 
+-static const struct zxdg_toplevel_v6_interface sl_xdg_toplevel_implementation =
++static const struct xdg_toplevel_interface sl_xdg_toplevel_implementation =
+     {sl_xdg_toplevel_destroy,          sl_xdg_toplevel_set_parent,
+      sl_xdg_toplevel_set_title,        sl_xdg_toplevel_set_app_id,
+      sl_xdg_toplevel_show_window_menu, sl_xdg_toplevel_move,
+@@ -320,33 +320,33 @@ static const struct zxdg_toplevel_v6_interface sl_xdg_toplevel_implementation =
+      sl_xdg_toplevel_unset_fullscreen, sl_xdg_toplevel_set_minimized};
+ 
+ static void sl_xdg_toplevel_configure(void* data,
+-                                      struct zxdg_toplevel_v6* xdg_toplevel,
++                                      struct xdg_toplevel* xdg_toplevel,
+                                       int32_t width,
+                                       int32_t height,
+                                       struct wl_array* states) {
+   struct sl_host_xdg_toplevel* host =
+-      zxdg_toplevel_v6_get_user_data(xdg_toplevel);
++      xdg_toplevel_get_user_data(xdg_toplevel);
+   double scale = host->ctx->scale;
+ 
+-  zxdg_toplevel_v6_send_configure(host->resource, width * scale, height * scale,
++  xdg_toplevel_send_configure(host->resource, width * scale, height * scale,
+                                   states);
+ }
+ 
+ static void sl_xdg_toplevel_close(void* data,
+-                                  struct zxdg_toplevel_v6* xdg_toplevel) {
++                                  struct xdg_toplevel* xdg_toplevel) {
+   struct sl_host_xdg_toplevel* host =
+-      zxdg_toplevel_v6_get_user_data(xdg_toplevel);
++      xdg_toplevel_get_user_data(xdg_toplevel);
+ 
+-  zxdg_toplevel_v6_send_close(host->resource);
++  xdg_toplevel_send_close(host->resource);
+ }
+ 
+-static const struct zxdg_toplevel_v6_listener sl_xdg_toplevel_listener = {
++static const struct xdg_toplevel_listener sl_xdg_toplevel_listener = {
+     sl_xdg_toplevel_configure, sl_xdg_toplevel_close};
+ 
+ static void sl_destroy_host_xdg_toplevel(struct wl_resource* resource) {
+   struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_toplevel_v6_destroy(host->proxy);
++  xdg_toplevel_destroy(host->proxy);
+   wl_resource_set_user_data(resource, NULL);
+   free(host);
+ }
+@@ -367,14 +367,15 @@ static void sl_xdg_surface_get_toplevel(struct wl_client* client,
+ 
+   host_xdg_toplevel->ctx = host->ctx;
+   host_xdg_toplevel->resource =
+-      wl_resource_create(client, &zxdg_toplevel_v6_interface, 1, id);
++      wl_resource_create(client, &xdg_toplevel_interface,
++                         wl_resource_get_version(resource), id);
+   wl_resource_set_implementation(
+       host_xdg_toplevel->resource, &sl_xdg_toplevel_implementation,
+       host_xdg_toplevel, sl_destroy_host_xdg_toplevel);
+-  host_xdg_toplevel->proxy = zxdg_surface_v6_get_toplevel(host->proxy);
+-  zxdg_toplevel_v6_set_user_data(host_xdg_toplevel->proxy, host_xdg_toplevel);
+-  zxdg_toplevel_v6_add_listener(host_xdg_toplevel->proxy,
+-                                &sl_xdg_toplevel_listener, host_xdg_toplevel);
++  host_xdg_toplevel->proxy = xdg_surface_get_toplevel(host->proxy);
++  xdg_toplevel_set_user_data(host_xdg_toplevel->proxy, host_xdg_toplevel);
++  xdg_toplevel_add_listener(host_xdg_toplevel->proxy,
++                            &sl_xdg_toplevel_listener, host_xdg_toplevel);
+ }
+ 
+ static void sl_xdg_surface_get_popup(struct wl_client* client,
+@@ -394,15 +395,16 @@ static void sl_xdg_surface_get_popup(struct wl_client* client,
+ 
+   host_xdg_popup->ctx = host->ctx;
+   host_xdg_popup->resource =
+-      wl_resource_create(client, &zxdg_popup_v6_interface, 1, id);
++      wl_resource_create(client, &xdg_popup_interface,
++                         wl_resource_get_version(resource), id);
+   wl_resource_set_implementation(host_xdg_popup->resource,
+                                  &sl_xdg_popup_implementation, host_xdg_popup,
+                                  sl_destroy_host_xdg_popup);
+-  host_xdg_popup->proxy = zxdg_surface_v6_get_popup(
++  host_xdg_popup->proxy = xdg_surface_get_popup(
+       host->proxy, host_parent->proxy, host_positioner->proxy);
+-  zxdg_popup_v6_set_user_data(host_xdg_popup->proxy, host_xdg_popup);
+-  zxdg_popup_v6_add_listener(host_xdg_popup->proxy, &sl_xdg_popup_listener,
+-                             host_xdg_popup);
++  xdg_popup_set_user_data(host_xdg_popup->proxy, host_xdg_popup);
++  xdg_popup_add_listener(host_xdg_popup->proxy, &sl_xdg_popup_listener,
++                         host_xdg_popup);
+ }
+ 
+ static void sl_xdg_surface_set_window_geometry(struct wl_client* client,
+@@ -420,7 +422,7 @@ static void sl_xdg_surface_set_window_geometry(struct wl_client* client,
+   x2 = (x + width) / scale;
+   y2 = (y + height) / scale;
+ 
+-  zxdg_surface_v6_set_window_geometry(host->proxy, x1, y1, x2 - x1, y2 - y1);
++  xdg_surface_set_window_geometry(host->proxy, x1, y1, x2 - x1, y2 - y1);
+ }
+ 
+ static void sl_xdg_surface_ack_configure(struct wl_client* client,
+@@ -428,63 +430,64 @@ static void sl_xdg_surface_ack_configure(struct wl_client* client,
+                                          uint32_t serial) {
+   struct sl_host_xdg_surface* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_surface_v6_ack_configure(host->proxy, serial);
++  xdg_surface_ack_configure(host->proxy, serial);
+ }
+ 
+-static const struct zxdg_surface_v6_interface sl_xdg_surface_implementation = {
++static const struct xdg_surface_interface sl_xdg_surface_implementation = {
+     sl_xdg_surface_destroy, sl_xdg_surface_get_toplevel,
+     sl_xdg_surface_get_popup, sl_xdg_surface_set_window_geometry,
+     sl_xdg_surface_ack_configure};
+ 
+ static void sl_xdg_surface_configure(void* data,
+-                                     struct zxdg_surface_v6* xdg_surface,
++                                     struct xdg_surface* xdg_surface,
+                                      uint32_t serial) {
+-  struct sl_host_xdg_surface* host = zxdg_surface_v6_get_user_data(xdg_surface);
++  struct sl_host_xdg_surface* host = xdg_surface_get_user_data(xdg_surface);
+ 
+-  zxdg_surface_v6_send_configure(host->resource, serial);
++  xdg_surface_send_configure(host->resource, serial);
+ }
+ 
+-static const struct zxdg_surface_v6_listener sl_xdg_surface_listener = {
++static const struct xdg_surface_listener sl_xdg_surface_listener = {
+     sl_xdg_surface_configure};
+ 
+ static void sl_destroy_host_xdg_surface(struct wl_resource* resource) {
+   struct sl_host_xdg_surface* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_surface_v6_destroy(host->proxy);
++  xdg_surface_destroy(host->proxy);
+   wl_resource_set_user_data(resource, NULL);
+   free(host);
+ }
+ 
+-static void sl_xdg_shell_destroy(struct wl_client* client,
++static void sl_xdg_wm_base_destroy(struct wl_client* client,
+                                  struct wl_resource* resource) {
+   wl_resource_destroy(resource);
+ }
+ 
+-static void sl_xdg_shell_create_positioner(struct wl_client* client,
++static void sl_xdg_wm_base_create_positioner(struct wl_client* client,
+                                            struct wl_resource* resource,
+                                            uint32_t id) {
+-  struct sl_host_xdg_shell* host = wl_resource_get_user_data(resource);
++  struct sl_host_xdg_wm_base* host = wl_resource_get_user_data(resource);
+   struct sl_host_xdg_positioner* host_xdg_positioner;
+ 
+   host_xdg_positioner = malloc(sizeof(*host_xdg_positioner));
+   assert(host_xdg_positioner);
+ 
+   host_xdg_positioner->ctx = host->ctx;
+-  host_xdg_positioner->resource =
+-      wl_resource_create(client, &zxdg_positioner_v6_interface, 1, id);
++  host_xdg_positioner->resource = wl_resource_create(
++      client, &xdg_positioner_interface,
++      wl_resource_get_version(resource), id);
+   wl_resource_set_implementation(
+       host_xdg_positioner->resource, &sl_xdg_positioner_implementation,
+       host_xdg_positioner, sl_destroy_host_xdg_positioner);
+-  host_xdg_positioner->proxy = zxdg_shell_v6_create_positioner(host->proxy);
+-  zxdg_positioner_v6_set_user_data(host_xdg_positioner->proxy,
+-                                   host_xdg_positioner);
++  host_xdg_positioner->proxy = xdg_wm_base_create_positioner(host->proxy);
++  xdg_positioner_set_user_data(host_xdg_positioner->proxy,
++                               host_xdg_positioner);
+ }
+ 
+-static void sl_xdg_shell_get_xdg_surface(struct wl_client* client,
++static void sl_xdg_wm_base_get_xdg_surface(struct wl_client* client,
+                                          struct wl_resource* resource,
+                                          uint32_t id,
+                                          struct wl_resource* surface_resource) {
+-  struct sl_host_xdg_shell* host = wl_resource_get_user_data(resource);
++  struct sl_host_xdg_wm_base* host = wl_resource_get_user_data(resource);
+   struct sl_host_surface* host_surface =
+       wl_resource_get_user_data(surface_resource);
+   struct sl_host_xdg_surface* host_xdg_surface;
+@@ -493,71 +496,75 @@ static void sl_xdg_shell_get_xdg_surface(struct wl_client* client,
+   assert(host_xdg_surface);
+ 
+   host_xdg_surface->ctx = host->ctx;
+-  host_xdg_surface->resource =
+-      wl_resource_create(client, &zxdg_surface_v6_interface, 1, id);
++  host_xdg_surface->resource = wl_resource_create(
++      client, &xdg_surface_interface,
++      wl_resource_get_version(resource), id);
+   wl_resource_set_implementation(host_xdg_surface->resource,
+                                  &sl_xdg_surface_implementation,
+                                  host_xdg_surface, sl_destroy_host_xdg_surface);
+   host_xdg_surface->proxy =
+-      zxdg_shell_v6_get_xdg_surface(host->proxy, host_surface->proxy);
+-  zxdg_surface_v6_set_user_data(host_xdg_surface->proxy, host_xdg_surface);
+-  zxdg_surface_v6_add_listener(host_xdg_surface->proxy,
+-                               &sl_xdg_surface_listener, host_xdg_surface);
++      xdg_wm_base_get_xdg_surface(host->proxy, host_surface->proxy);
++  xdg_surface_set_user_data(host_xdg_surface->proxy, host_xdg_surface);
++  xdg_surface_add_listener(host_xdg_surface->proxy,
++                           &sl_xdg_surface_listener, host_xdg_surface);
+   host_surface->has_role = 1;
+ }
+ 
+-static void sl_xdg_shell_pong(struct wl_client* client,
++static void sl_xdg_wm_base_pong(struct wl_client* client,
+                               struct wl_resource* resource,
+                               uint32_t serial) {
+-  struct sl_host_xdg_shell* host = wl_resource_get_user_data(resource);
++  struct sl_host_xdg_wm_base* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_shell_v6_pong(host->proxy, serial);
++  xdg_wm_base_pong(host->proxy, serial);
+ }
+ 
+-static const struct zxdg_shell_v6_interface sl_xdg_shell_implementation = {
+-    sl_xdg_shell_destroy, sl_xdg_shell_create_positioner,
+-    sl_xdg_shell_get_xdg_surface, sl_xdg_shell_pong};
++static const struct xdg_wm_base_interface sl_xdg_wm_base_implementation = {
++    sl_xdg_wm_base_destroy, sl_xdg_wm_base_create_positioner,
++    sl_xdg_wm_base_get_xdg_surface, sl_xdg_wm_base_pong};
+ 
+-static void sl_xdg_shell_ping(void* data,
+-                              struct zxdg_shell_v6* xdg_shell,
++static void sl_xdg_wm_base_ping(void* data,
++                              struct xdg_wm_base* xdg_wm_base,
+                               uint32_t serial) {
+-  struct sl_host_xdg_shell* host = zxdg_shell_v6_get_user_data(xdg_shell);
++  struct sl_host_xdg_wm_base* host = xdg_wm_base_get_user_data(xdg_wm_base);
+ 
+-  zxdg_shell_v6_send_ping(host->resource, serial);
++  xdg_wm_base_send_ping(host->resource, serial);
+ }
+ 
+-static const struct zxdg_shell_v6_listener sl_xdg_shell_listener = {
+-    sl_xdg_shell_ping};
++static const struct xdg_wm_base_listener sl_xdg_wm_base_listener = {
++    sl_xdg_wm_base_ping};
+ 
+-static void sl_destroy_host_xdg_shell(struct wl_resource* resource) {
+-  struct sl_host_xdg_shell* host = wl_resource_get_user_data(resource);
++static void sl_destroy_host_xdg_wm_base(struct wl_resource* resource) {
++  struct sl_host_xdg_wm_base* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_shell_v6_destroy(host->proxy);
++  xdg_wm_base_destroy(host->proxy);
+   wl_resource_set_user_data(resource, NULL);
+   free(host);
+ }
+ 
+-static void sl_bind_host_xdg_shell(struct wl_client* client,
++static void sl_bind_host_xdg_wm_base(struct wl_client* client,
+                                    void* data,
+                                    uint32_t version,
+                                    uint32_t id) {
+   struct sl_context* ctx = (struct sl_context*)data;
+-  struct sl_host_xdg_shell* host;
++  struct sl_host_xdg_wm_base* host;
+ 
+   host = malloc(sizeof(*host));
+   assert(host);
+   host->ctx = ctx;
+-  host->resource = wl_resource_create(client, &zxdg_shell_v6_interface, 1, id);
+-  wl_resource_set_implementation(host->resource, &sl_xdg_shell_implementation,
+-                                 host, sl_destroy_host_xdg_shell);
++  host->resource = wl_resource_create(client, &xdg_wm_base_interface,
++				      ctx->xdg_wm_base->id, id);
++  wl_resource_set_implementation(host->resource, &sl_xdg_wm_base_implementation,
++                                 host, sl_destroy_host_xdg_wm_base);
+   host->proxy =
+       wl_registry_bind(wl_display_get_registry(ctx->display),
+-                       ctx->xdg_shell->id, &zxdg_shell_v6_interface, 1);
+-  zxdg_shell_v6_set_user_data(host->proxy, host);
+-  zxdg_shell_v6_add_listener(host->proxy, &sl_xdg_shell_listener, host);
++                       ctx->xdg_wm_base->id, &xdg_wm_base_interface,
++                       ctx->xdg_wm_base->version);
++  xdg_wm_base_set_user_data(host->proxy, host);
++  xdg_wm_base_add_listener(host->proxy, &sl_xdg_wm_base_listener, host);
+ }
+ 
+-struct sl_global* sl_xdg_shell_global_create(struct sl_context* ctx) {
+-  return sl_global_create(ctx, &zxdg_shell_v6_interface, 1, ctx,
+-                          sl_bind_host_xdg_shell);
++struct sl_global* sl_xdg_wm_base_global_create(struct sl_context* ctx) {
++  return sl_global_create(ctx, &xdg_wm_base_interface,
++                          ctx->xdg_wm_base->version, ctx,
++                          sl_bind_host_xdg_wm_base);
+ }
+diff --git a/vm_tools/sommelier/sommelier.c b/vm_tools/sommelier/sommelier.c
+index d87bced03..5e03d8978 100644
+--- a/vm_tools/sommelier/sommelier.c
++++ b/vm_tools/sommelier/sommelier.c
+@@ -35,7 +35,7 @@
+ #include "relative-pointer-unstable-v1-client-protocol.h"
+ #include "text-input-unstable-v1-client-protocol.h"
+ #include "viewporter-client-protocol.h"
+-#include "xdg-shell-unstable-v6-client-protocol.h"
++#include "xdg-shell-client-protocol.h"
+ 
+ // Check that required macro definitions exist.
+ #ifndef XWAYLAND_PATH
+@@ -272,14 +272,14 @@ void sl_sync_point_destroy(struct sl_sync_point* sync_point) {
+   free(sync_point);
+ }
+ 
+-static void sl_internal_xdg_shell_ping(void* data,
+-                                       struct zxdg_shell_v6* xdg_shell,
++static void sl_internal_xdg_wm_base_ping(void* data,
++                                       struct xdg_wm_base* xdg_wm_base,
+                                        uint32_t serial) {
+-  zxdg_shell_v6_pong(xdg_shell, serial);
++  xdg_wm_base_pong(xdg_wm_base, serial);
+ }
+ 
+-static const struct zxdg_shell_v6_listener sl_internal_xdg_shell_listener = {
+-    sl_internal_xdg_shell_ping};
++static const struct xdg_wm_base_listener sl_internal_xdg_wm_base_listener = {
++    sl_internal_xdg_wm_base_ping};
+ 
+ static void sl_send_configure_notify(struct sl_window* window) {
+   xcb_configure_notify_event_t event = {
+@@ -442,8 +442,8 @@ int sl_process_pending_configure_acks(struct sl_window* window,
+   }
+ 
+   if (window->xdg_surface) {
+-    zxdg_surface_v6_ack_configure(window->xdg_surface,
+-                                  window->pending_config.serial);
++    xdg_surface_ack_configure(window->xdg_surface,
++                              window->pending_config.serial);
+   }
+   window->pending_config.serial = 0;
+ 
+@@ -454,8 +454,8 @@ int sl_process_pending_configure_acks(struct sl_window* window,
+ }
+ 
+ static void sl_internal_xdg_surface_configure(
+-    void* data, struct zxdg_surface_v6* xdg_surface, uint32_t serial) {
+-  struct sl_window* window = zxdg_surface_v6_get_user_data(xdg_surface);
++    void* data, struct xdg_surface* xdg_surface, uint32_t serial) {
++  struct sl_window* window = xdg_surface_get_user_data(xdg_surface);
+ 
+   window->next_config.serial = serial;
+   if (!window->pending_config.serial) {
+@@ -476,16 +476,16 @@ static void sl_internal_xdg_surface_configure(
+   }
+ }
+ 
+-static const struct zxdg_surface_v6_listener sl_internal_xdg_surface_listener =
++static const struct xdg_surface_listener sl_internal_xdg_surface_listener =
+     {sl_internal_xdg_surface_configure};
+ 
+ static void sl_internal_xdg_toplevel_configure(
+     void* data,
+-    struct zxdg_toplevel_v6* xdg_toplevel,
++    struct xdg_toplevel* xdg_toplevel,
+     int32_t width,
+     int32_t height,
+     struct wl_array* states) {
+-  struct sl_window* window = zxdg_toplevel_v6_get_user_data(xdg_toplevel);
++  struct sl_window* window = xdg_toplevel_get_user_data(xdg_toplevel);
+   int activated = 0;
+   uint32_t* state;
+   int i = 0;
+@@ -515,21 +515,21 @@ static void sl_internal_xdg_toplevel_configure(
+ 
+   window->allow_resize = 1;
+   wl_array_for_each(state, states) {
+-    if (*state == ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN) {
++    if (*state == XDG_TOPLEVEL_STATE_FULLSCREEN) {
+       window->allow_resize = 0;
+       window->next_config.states[i++] =
+           window->ctx->atoms[ATOM_NET_WM_STATE_FULLSCREEN].value;
+     }
+-    if (*state == ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED) {
++    if (*state == XDG_TOPLEVEL_STATE_MAXIMIZED) {
+       window->allow_resize = 0;
+       window->next_config.states[i++] =
+           window->ctx->atoms[ATOM_NET_WM_STATE_MAXIMIZED_VERT].value;
+       window->next_config.states[i++] =
+           window->ctx->atoms[ATOM_NET_WM_STATE_MAXIMIZED_HORZ].value;
+     }
+-    if (*state == ZXDG_TOPLEVEL_V6_STATE_ACTIVATED)
++    if (*state == XDG_TOPLEVEL_STATE_ACTIVATED)
+       activated = 1;
+-    if (*state == ZXDG_TOPLEVEL_V6_STATE_RESIZING)
++    if (*state == XDG_TOPLEVEL_STATE_RESIZING)
+       window->allow_resize = 0;
+   }
+ 
+@@ -545,8 +545,8 @@ static void sl_internal_xdg_toplevel_configure(
+ }
+ 
+ static void sl_internal_xdg_toplevel_close(
+-    void* data, struct zxdg_toplevel_v6* xdg_toplevel) {
+-  struct sl_window* window = zxdg_toplevel_v6_get_user_data(xdg_toplevel);
++    void* data, struct xdg_toplevel* xdg_toplevel) {
++  struct sl_window* window = xdg_toplevel_get_user_data(xdg_toplevel);
+   xcb_client_message_event_t event = {
+       .response_type = XCB_CLIENT_MESSAGE,
+       .format = 32,
+@@ -563,21 +563,21 @@ static void sl_internal_xdg_toplevel_close(
+                  XCB_EVENT_MASK_NO_EVENT, (const char*)&event);
+ }
+ 
+-static const struct zxdg_toplevel_v6_listener
++static const struct xdg_toplevel_listener
+     sl_internal_xdg_toplevel_listener = {sl_internal_xdg_toplevel_configure,
+                                          sl_internal_xdg_toplevel_close};
+ 
+ static void sl_internal_xdg_popup_configure(void* data,
+-                                            struct zxdg_popup_v6* xdg_popup,
++                                            struct xdg_popup* xdg_popup,
+                                             int32_t x,
+                                             int32_t y,
+                                             int32_t width,
+                                             int32_t height) {}
+ 
+ static void sl_internal_xdg_popup_done(void* data,
+-                                       struct zxdg_popup_v6* zxdg_popup_v6) {}
++                                       struct xdg_popup* xdg_popup) {}
+ 
+-static const struct zxdg_popup_v6_listener sl_internal_xdg_popup_listener = {
++static const struct xdg_popup_listener sl_internal_xdg_popup_listener = {
+     sl_internal_xdg_popup_configure, sl_internal_xdg_popup_done};
+ 
+ static void sl_window_set_wm_state(struct sl_window* window, int state) {
+@@ -645,15 +645,15 @@ void sl_window_update(struct sl_window* window) {
+       window->aura_surface = NULL;
+     }
+     if (window->xdg_toplevel) {
+-      zxdg_toplevel_v6_destroy(window->xdg_toplevel);
++      xdg_toplevel_destroy(window->xdg_toplevel);
+       window->xdg_toplevel = NULL;
+     }
+     if (window->xdg_popup) {
+-      zxdg_popup_v6_destroy(window->xdg_popup);
++      xdg_popup_destroy(window->xdg_popup);
+       window->xdg_popup = NULL;
+     }
+     if (window->xdg_surface) {
+-      zxdg_surface_v6_destroy(window->xdg_surface);
++      xdg_surface_destroy(window->xdg_surface);
+       window->xdg_surface = NULL;
+     }
+     window->realized = 0;
+@@ -664,8 +664,8 @@ void sl_window_update(struct sl_window* window) {
+   assert(host_surface);
+   assert(!host_surface->has_role);
+ 
+-  assert(ctx->xdg_shell);
+-  assert(ctx->xdg_shell->internal);
++  assert(ctx->xdg_wm_base);
++  assert(ctx->xdg_wm_base->internal);
+ 
+   if (window->managed) {
+     if (window->transient_for != XCB_WINDOW_NONE) {
+@@ -727,11 +727,11 @@ void sl_window_update(struct sl_window* window) {
+   }
+ 
+   if (!window->xdg_surface) {
+-    window->xdg_surface = zxdg_shell_v6_get_xdg_surface(
+-        ctx->xdg_shell->internal, host_surface->proxy);
+-    zxdg_surface_v6_set_user_data(window->xdg_surface, window);
+-    zxdg_surface_v6_add_listener(window->xdg_surface,
+-                                 &sl_internal_xdg_surface_listener, window);
++    window->xdg_surface = xdg_wm_base_get_xdg_surface(
++        ctx->xdg_wm_base->internal, host_surface->proxy);
++    xdg_surface_set_user_data(window->xdg_surface, window);
++    xdg_surface_add_listener(window->xdg_surface,
++                             &sl_internal_xdg_surface_listener, window);
+   }
+ 
+   if (ctx->aura_shell) {
+@@ -761,50 +761,50 @@ void sl_window_update(struct sl_window* window) {
+   // window is closed.
+   if (ctx->xwayland || !parent) {
+     if (!window->xdg_toplevel) {
+-      window->xdg_toplevel = zxdg_surface_v6_get_toplevel(window->xdg_surface);
+-      zxdg_toplevel_v6_set_user_data(window->xdg_toplevel, window);
+-      zxdg_toplevel_v6_add_listener(window->xdg_toplevel,
++      window->xdg_toplevel = xdg_surface_get_toplevel(window->xdg_surface);
++      xdg_toplevel_set_user_data(window->xdg_toplevel, window);
++      xdg_toplevel_add_listener(window->xdg_toplevel,
+                                     &sl_internal_xdg_toplevel_listener, window);
+     }
+     if (parent)
+-      zxdg_toplevel_v6_set_parent(window->xdg_toplevel, parent->xdg_toplevel);
++      xdg_toplevel_set_parent(window->xdg_toplevel, parent->xdg_toplevel);
+     if (window->name)
+-      zxdg_toplevel_v6_set_title(window->xdg_toplevel, window->name);
++      xdg_toplevel_set_title(window->xdg_toplevel, window->name);
+     if (window->size_flags & P_MIN_SIZE) {
+-      zxdg_toplevel_v6_set_min_size(window->xdg_toplevel,
++      xdg_toplevel_set_min_size(window->xdg_toplevel,
+                                     window->min_width / ctx->scale,
+                                     window->min_height / ctx->scale);
+     }
+     if (window->size_flags & P_MAX_SIZE) {
+-      zxdg_toplevel_v6_set_max_size(window->xdg_toplevel,
++      xdg_toplevel_set_max_size(window->xdg_toplevel,
+                                     window->max_width / ctx->scale,
+                                     window->max_height / ctx->scale);
+     }
+     if (window->maximized) {
+-      zxdg_toplevel_v6_set_maximized(window->xdg_toplevel);
++      xdg_toplevel_set_maximized(window->xdg_toplevel);
+     }
+   } else if (!window->xdg_popup) {
+-    struct zxdg_positioner_v6* positioner;
++    struct xdg_positioner* positioner;
+ 
+-    positioner = zxdg_shell_v6_create_positioner(ctx->xdg_shell->internal);
++    positioner = xdg_wm_base_create_positioner(ctx->xdg_wm_base->internal);
+     assert(positioner);
+-    zxdg_positioner_v6_set_anchor(
++    xdg_positioner_set_anchor(
+         positioner,
+-        ZXDG_POSITIONER_V6_ANCHOR_TOP | ZXDG_POSITIONER_V6_ANCHOR_LEFT);
+-    zxdg_positioner_v6_set_gravity(
++        XDG_POSITIONER_ANCHOR_TOP | XDG_POSITIONER_ANCHOR_LEFT);
++    xdg_positioner_set_gravity(
+         positioner,
+-        ZXDG_POSITIONER_V6_GRAVITY_BOTTOM | ZXDG_POSITIONER_V6_GRAVITY_RIGHT);
+-    zxdg_positioner_v6_set_anchor_rect(
++        XDG_POSITIONER_GRAVITY_BOTTOM | XDG_POSITIONER_GRAVITY_RIGHT);
++    xdg_positioner_set_anchor_rect(
+         positioner, (window->x - parent->x) / ctx->scale,
+         (window->y - parent->y) / ctx->scale, 1, 1);
+ 
+-    window->xdg_popup = zxdg_surface_v6_get_popup(
++    window->xdg_popup = xdg_surface_get_popup(
+         window->xdg_surface, parent->xdg_surface, positioner);
+-    zxdg_popup_v6_set_user_data(window->xdg_popup, window);
+-    zxdg_popup_v6_add_listener(window->xdg_popup,
++    xdg_popup_set_user_data(window->xdg_popup, window);
++    xdg_popup_add_listener(window->xdg_popup,
+                                &sl_internal_xdg_popup_listener, window);
+ 
+-    zxdg_positioner_v6_destroy(positioner);
++    xdg_positioner_destroy(positioner);
+   }
+ 
+   if ((window->size_flags & (US_POSITION | P_POSITION)) && parent &&
+@@ -1168,22 +1168,23 @@ static void sl_registry_handler(void* data,
+       data_device_manager->host_global =
+           sl_data_device_manager_global_create(ctx);
+     }
+-  } else if (strcmp(interface, "zxdg_shell_v6") == 0) {
+-    struct sl_xdg_shell* xdg_shell = malloc(sizeof(struct sl_xdg_shell));
+-    assert(xdg_shell);
+-    xdg_shell->ctx = ctx;
+-    xdg_shell->id = id;
+-    xdg_shell->internal = NULL;
+-    xdg_shell->host_global = NULL;
+-    assert(!ctx->xdg_shell);
+-    ctx->xdg_shell = xdg_shell;
++  } else if (strcmp(interface, "xdg_wm_base") == 0) {
++    struct sl_xdg_wm_base* xdg_wm_base = malloc(sizeof(struct sl_xdg_wm_base));
++    assert(xdg_wm_base);
++    xdg_wm_base->ctx = ctx;
++    xdg_wm_base->id = id;
++    xdg_wm_base->version = MIN(2, version);
++    xdg_wm_base->internal = NULL;
++    xdg_wm_base->host_global = NULL;
++    assert(!ctx->xdg_wm_base);
++    ctx->xdg_wm_base = xdg_wm_base;
+     if (ctx->xwayland) {
+-      xdg_shell->internal =
+-          wl_registry_bind(registry, id, &zxdg_shell_v6_interface, 1);
+-      zxdg_shell_v6_add_listener(xdg_shell->internal,
+-                                 &sl_internal_xdg_shell_listener, NULL);
++      xdg_wm_base->internal =
++          wl_registry_bind(registry, id, &xdg_wm_base_interface, 1);
++      xdg_wm_base_add_listener(xdg_wm_base->internal,
++                                 &sl_internal_xdg_wm_base_listener, NULL);
+     } else {
+-      xdg_shell->host_global = sl_xdg_shell_global_create(ctx);
++      xdg_wm_base->host_global = sl_xdg_wm_base_global_create(ctx);
+     }
+   } else if (strcmp(interface, "zaura_shell") == 0) {
+     if (version >= MIN_AURA_SHELL_VERSION) {
+@@ -1290,13 +1291,13 @@ static void sl_registry_remover(void* data,
+     ctx->data_device_manager = NULL;
+     return;
+   }
+-  if (ctx->xdg_shell && ctx->xdg_shell->id == id) {
+-    if (ctx->xdg_shell->host_global)
+-      sl_global_destroy(ctx->xdg_shell->host_global);
+-    if (ctx->xdg_shell->internal)
+-      zxdg_shell_v6_destroy(ctx->xdg_shell->internal);
+-    free(ctx->xdg_shell);
+-    ctx->xdg_shell = NULL;
++  if (ctx->xdg_wm_base && ctx->xdg_wm_base->id == id) {
++    if (ctx->xdg_wm_base->host_global)
++      sl_global_destroy(ctx->xdg_wm_base->host_global);
++    if (ctx->xdg_wm_base->internal)
++      xdg_wm_base_destroy(ctx->xdg_wm_base->internal);
++    free(ctx->xdg_wm_base);
++    ctx->xdg_wm_base = NULL;
+     return;
+   }
+   if (ctx->aura_shell && ctx->aura_shell->id == id) {
+@@ -1458,11 +1459,11 @@ static void sl_destroy_window(struct sl_window* window) {
+   }
+ 
+   if (window->xdg_popup)
+-    zxdg_popup_v6_destroy(window->xdg_popup);
++    xdg_popup_destroy(window->xdg_popup);
+   if (window->xdg_toplevel)
+-    zxdg_toplevel_v6_destroy(window->xdg_toplevel);
++    xdg_toplevel_destroy(window->xdg_toplevel);
+   if (window->xdg_surface)
+-    zxdg_surface_v6_destroy(window->xdg_surface);
++    xdg_surface_destroy(window->xdg_surface);
+   if (window->aura_surface)
+     zaura_surface_destroy(window->aura_surface);
+ 
+@@ -1906,15 +1907,15 @@ static void sl_handle_configure_request(struct sl_context* ctx,
+   // that matching contents will arrive.
+   if (window->xdg_toplevel) {
+     if (window->pending_config.serial) {
+-      zxdg_surface_v6_ack_configure(window->xdg_surface,
+-                                    window->pending_config.serial);
++      xdg_surface_ack_configure(window->xdg_surface,
++                                window->pending_config.serial);
+       window->pending_config.serial = 0;
+       window->pending_config.mask = 0;
+       window->pending_config.states_length = 0;
+     }
+     if (window->next_config.serial) {
+-      zxdg_surface_v6_ack_configure(window->xdg_surface,
+-                                    window->next_config.serial);
++      xdg_surface_ack_configure(window->xdg_surface,
++                                window->next_config.serial);
+       window->next_config.serial = 0;
+       window->next_config.mask = 0;
+       window->next_config.states_length = 0;
+@@ -2035,23 +2036,23 @@ static void sl_handle_configure_notify(struct sl_context* ctx,
+ static uint32_t sl_resize_edge(int net_wm_moveresize_size) {
+   switch (net_wm_moveresize_size) {
+     case NET_WM_MOVERESIZE_SIZE_TOPLEFT:
+-      return ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_LEFT;
++      return XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
+     case NET_WM_MOVERESIZE_SIZE_TOP:
+-      return ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP;
++      return XDG_TOPLEVEL_RESIZE_EDGE_TOP;
+     case NET_WM_MOVERESIZE_SIZE_TOPRIGHT:
+-      return ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_RIGHT;
++      return XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
+     case NET_WM_MOVERESIZE_SIZE_RIGHT:
+-      return ZXDG_TOPLEVEL_V6_RESIZE_EDGE_RIGHT;
++      return XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
+     case NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT:
+-      return ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_RIGHT;
++      return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
+     case NET_WM_MOVERESIZE_SIZE_BOTTOM:
+-      return ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM;
++      return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
+     case NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT:
+-      return ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_LEFT;
++      return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
+     case NET_WM_MOVERESIZE_SIZE_LEFT:
+-      return ZXDG_TOPLEVEL_V6_RESIZE_EDGE_LEFT;
++      return XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
+     default:
+-      return ZXDG_TOPLEVEL_V6_RESIZE_EDGE_NONE;
++      return XDG_TOPLEVEL_RESIZE_EDGE_NONE;
+   }
+ }
+ 
+@@ -2098,15 +2099,15 @@ static void sl_handle_client_message(struct sl_context* ctx,
+         return;
+ 
+       if (event->data.data32[2] == NET_WM_MOVERESIZE_MOVE) {
+-        zxdg_toplevel_v6_move(window->xdg_toplevel, seat->proxy,
++        xdg_toplevel_move(window->xdg_toplevel, seat->proxy,
+                               seat->seat->last_serial);
+       } else {
+         uint32_t edge = sl_resize_edge(event->data.data32[2]);
+ 
+-        if (edge == ZXDG_TOPLEVEL_V6_RESIZE_EDGE_NONE)
++        if (edge == XDG_TOPLEVEL_RESIZE_EDGE_NONE)
+           return;
+ 
+-        zxdg_toplevel_v6_resize(window->xdg_toplevel, seat->proxy,
++        xdg_toplevel_resize(window->xdg_toplevel, seat->proxy,
+                                 seat->seat->last_serial, edge);
+       }
+     }
+@@ -2125,24 +2126,24 @@ static void sl_handle_client_message(struct sl_context* ctx,
+ 
+       if (changed[ATOM_NET_WM_STATE_FULLSCREEN]) {
+         if (action == NET_WM_STATE_ADD)
+-          zxdg_toplevel_v6_set_fullscreen(window->xdg_toplevel, NULL);
++          xdg_toplevel_set_fullscreen(window->xdg_toplevel, NULL);
+         else if (action == NET_WM_STATE_REMOVE)
+-          zxdg_toplevel_v6_unset_fullscreen(window->xdg_toplevel);
++          xdg_toplevel_unset_fullscreen(window->xdg_toplevel);
+       }
+ 
+       if (changed[ATOM_NET_WM_STATE_MAXIMIZED_VERT] &&
+           changed[ATOM_NET_WM_STATE_MAXIMIZED_HORZ]) {
+         if (action == NET_WM_STATE_ADD)
+-          zxdg_toplevel_v6_set_maximized(window->xdg_toplevel);
++          xdg_toplevel_set_maximized(window->xdg_toplevel);
+         else if (action == NET_WM_STATE_REMOVE)
+-          zxdg_toplevel_v6_unset_maximized(window->xdg_toplevel);
++          xdg_toplevel_unset_maximized(window->xdg_toplevel);
+       }
+     }
+   } else if (event->type == ctx->atoms[ATOM_WM_CHANGE_STATE].value &&
+              event->data.data32[0] == WM_STATE_ICONIC) {
+     struct sl_window* window = sl_lookup_window(ctx, event->window);
+     if (window && window->xdg_toplevel) {
+-      zxdg_toplevel_v6_set_minimized(window->xdg_toplevel);
++      xdg_toplevel_set_minimized(window->xdg_toplevel);
+     }
+   }
+ }
+@@ -2155,7 +2156,7 @@ static void sl_handle_focus_in(struct sl_context* ctx,
+     // window was realized.
+     struct sl_window* parent = sl_lookup_window(ctx, window->transient_for);
+     if (parent && parent->xdg_toplevel && window->xdg_toplevel)
+-      zxdg_toplevel_v6_set_parent(window->xdg_toplevel, parent->xdg_toplevel);
++      xdg_toplevel_set_parent(window->xdg_toplevel, parent->xdg_toplevel);
+   }
+ }
+ 
+@@ -2373,9 +2374,9 @@ static void sl_handle_property_notify(struct sl_context* ctx,
+       return;
+ 
+     if (window->name) {
+-      zxdg_toplevel_v6_set_title(window->xdg_toplevel, window->name);
++      xdg_toplevel_set_title(window->xdg_toplevel, window->name);
+     } else {
+-      zxdg_toplevel_v6_set_title(window->xdg_toplevel, "");
++      xdg_toplevel_set_title(window->xdg_toplevel, "");
+     }
+   } else if (event->atom == XCB_ATOM_WM_CLASS) {
+     struct sl_window* window = sl_lookup_window(ctx, event->window);
+@@ -2427,19 +2428,19 @@ static void sl_handle_property_notify(struct sl_context* ctx,
+       return;
+ 
+     if (window->size_flags & P_MIN_SIZE) {
+-      zxdg_toplevel_v6_set_min_size(window->xdg_toplevel,
++      xdg_toplevel_set_min_size(window->xdg_toplevel,
+                                     window->min_width / ctx->scale,
+                                     window->min_height / ctx->scale);
+     } else {
+-      zxdg_toplevel_v6_set_min_size(window->xdg_toplevel, 0, 0);
++      xdg_toplevel_set_min_size(window->xdg_toplevel, 0, 0);
+     }
+ 
+     if (window->size_flags & P_MAX_SIZE) {
+-      zxdg_toplevel_v6_set_max_size(window->xdg_toplevel,
++      xdg_toplevel_set_max_size(window->xdg_toplevel,
+                                     window->max_width / ctx->scale,
+                                     window->max_height / ctx->scale);
+     } else {
+-      zxdg_toplevel_v6_set_max_size(window->xdg_toplevel, 0, 0);
++      xdg_toplevel_set_max_size(window->xdg_toplevel, 0, 0);
+     }
+   } else if (event->atom == XCB_ATOM_WM_HINTS) {
+     struct sl_window* window = sl_lookup_window(ctx, event->window);
+@@ -3536,7 +3537,7 @@ int main(int argc, char** argv) {
+       .shm = NULL,
+       .shell = NULL,
+       .data_device_manager = NULL,
+-      .xdg_shell = NULL,
++      .xdg_wm_base = NULL,
+       .aura_shell = NULL,
+       .viewporter = NULL,
+       .linux_dmabuf = NULL,
+diff --git a/vm_tools/sommelier/sommelier.h b/vm_tools/sommelier/sommelier.h
+index b851b5c8d..7e6daf773 100644
+--- a/vm_tools/sommelier/sommelier.h
++++ b/vm_tools/sommelier/sommelier.h
+@@ -31,7 +31,7 @@ struct sl_shell;
+ struct sl_data_device_manager;
+ struct sl_data_offer;
+ struct sl_data_source;
+-struct sl_xdg_shell;
++struct sl_xdg_wm_base;
+ struct sl_subcompositor;
+ struct sl_aura_shell;
+ struct sl_viewporter;
+@@ -99,7 +99,7 @@ struct sl_context {
+   struct sl_shm* shm;
+   struct sl_shell* shell;
+   struct sl_data_device_manager* data_device_manager;
+-  struct sl_xdg_shell* xdg_shell;
++  struct sl_xdg_wm_base* xdg_wm_base;
+   struct sl_aura_shell* aura_shell;
+   struct sl_viewporter* viewporter;
+   struct sl_linux_dmabuf* linux_dmabuf;
+@@ -373,11 +373,12 @@ struct sl_viewporter {
+   struct wp_viewporter* internal;
+ };
+ 
+-struct sl_xdg_shell {
++struct sl_xdg_wm_base {
+   struct sl_context* ctx;
+   uint32_t id;
++  uint32_t version;
+   struct sl_global* host_global;
+-  struct zxdg_shell_v6* internal;
++  struct xdg_wm_base* internal;
+ };
+ 
+ struct sl_aura_shell {
+@@ -476,9 +477,9 @@ struct sl_window {
+   int max_height;
+   struct sl_config next_config;
+   struct sl_config pending_config;
+-  struct zxdg_surface_v6* xdg_surface;
+-  struct zxdg_toplevel_v6* xdg_toplevel;
+-  struct zxdg_popup_v6* xdg_popup;
++  struct xdg_surface* xdg_surface;
++  struct xdg_toplevel* xdg_toplevel;
++  struct xdg_popup* xdg_popup;
+   struct zaura_surface* aura_surface;
+   struct wl_list link;
+ };
+@@ -522,7 +523,7 @@ struct sl_global* sl_data_device_manager_global_create(struct sl_context* ctx);
+ 
+ struct sl_global* sl_viewporter_global_create(struct sl_context* ctx);
+ 
+-struct sl_global* sl_xdg_shell_global_create(struct sl_context* ctx);
++struct sl_global* sl_xdg_wm_base_global_create(struct sl_context* ctx);
+ 
+ struct sl_global* sl_gtk_shell_global_create(struct sl_context* ctx);
+ 
+-- 
+2.25.1
+
diff --git a/pkgs/os-specific/linux/chromium-os/sommelier/0006-sommelier-make-building-demos-optional.patch b/pkgs/os-specific/linux/chromium-os/sommelier/0006-sommelier-make-building-demos-optional.patch
new file mode 100644
index 00000000000..277ffa47ce7
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/sommelier/0006-sommelier-make-building-demos-optional.patch
@@ -0,0 +1,100 @@
+From 8774d76f1b57092df9004d654fd075d7691b9f12 Mon Sep 17 00:00:00 2001
+From: Alyssa Ross <hi@alyssa.is>
+Date: Wed, 15 Jan 2020 21:36:43 +0000
+Subject: [PATCH 6/6] sommelier: make building demos optional
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+pkg-config was checked at GN evaluation time for libbrillo and
+libchrome, meaning that there was no way to build sommelier without
+them, even though they were only required for the demos, not for
+sommelier itself.
+
+Making the demo optional saves having to libbrillo and libchrome for
+the common case of building just sommelier, which themselves have lots
+of unusual dependencies.
+
+Thanks-to: Tomasz Ĺšniatowski <tsniatowski@vewd.com>
+---
+ vm_tools/sommelier/BUILD.gn | 54 ++++++++++++++++++++++---------------
+ 1 file changed, 32 insertions(+), 22 deletions(-)
+
+diff --git a/vm_tools/sommelier/BUILD.gn b/vm_tools/sommelier/BUILD.gn
+index 4330560a1..cbb752745 100644
+--- a/vm_tools/sommelier/BUILD.gn
++++ b/vm_tools/sommelier/BUILD.gn
+@@ -4,12 +4,20 @@
+ 
+ import("wayland_protocol.gni")
+ 
++declare_args() {
++  use_demos = true
++}
++
+ group("all") {
+   deps = [
+     ":sommelier",
+-    ":wayland_demo",
+-    ":x11_demo",
+   ]
++  if (use_demos) {
++    deps += [
++      ":wayland_demo",
++      ":x11_demo",
++    ]
++  }
+ }
+ 
+ if (!defined(peer_cmd_prefix)) {
+@@ -123,25 +131,27 @@ executable("sommelier") {
+   ]
+ }
+ 
+-executable("wayland_demo") {
+-  pkg_deps = [
+-    "libbrillo",
+-    "libchrome-${libbase_ver}",
+-    "wayland-client",
+-  ]
+-  libs = [ "wayland-client" ]
+-  sources = [
+-    "demos/wayland_demo.cc",
+-  ]
+-}
++if (use_demos) {
++  executable("wayland_demo") {
++    pkg_deps = [
++      "libbrillo",
++      "libchrome-${libbase_ver}",
++      "wayland-client",
++    ]
++    libs = [ "wayland-client" ]
++    sources = [
++      "demos/wayland_demo.cc",
++    ]
++  }
+ 
+-executable("x11_demo") {
+-  pkg_deps = [
+-    "libbrillo",
+-    "libchrome-${libbase_ver}",
+-  ]
+-  libs = [ "X11" ]
+-  sources = [
+-    "demos/x11_demo.cc",
+-  ]
++  executable("x11_demo") {
++    pkg_deps = [
++      "libbrillo",
++      "libchrome-${libbase_ver}",
++    ]
++    libs = [ "X11" ]
++    sources = [
++      "demos/x11_demo.cc",
++    ]
++  }
+ }
+-- 
+2.25.1
+
diff --git a/pkgs/os-specific/linux/chromium-os/sommelier/default.nix b/pkgs/os-specific/linux/chromium-os/sommelier/default.nix
new file mode 100644
index 00000000000..669bac81628
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/sommelier/default.nix
@@ -0,0 +1,38 @@
+{ common-mk, lib
+, mesa, grpc, openssl, libdrm, xlibs, protobuf, wayland, libxkbcommon, vm_protos
+, linuxHeaders, c-ares, zlib
+}:
+
+common-mk {
+  platformSubdir = "vm_tools/sommelier";
+
+  platform2Patches = [
+    ./0004-sommelier-don-t-leak-source-absolute-paths.patch
+    ./0005-sommelier-use-stable-xdg-shell-protocol.patch
+    ./0006-sommelier-make-building-demos-optional.patch
+  ];
+
+  buildInputs = [
+    mesa grpc openssl libdrm protobuf wayland libxkbcommon vm_protos
+    linuxHeaders c-ares zlib
+  ] ++ (with xlibs; [ pixman libxcb libX11 ]);
+
+  gnArgs.use_demos = false;
+
+  NIX_CFLAGS_COMPILE = [
+    "-Wno-error=sign-compare"
+    "-Wno-error=stringop-truncation"
+    "-Wno-error=class-memaccess"
+    "-Wno-error=maybe-uninitialized"
+  ];
+
+  installPhase = ''
+    mkdir -p $out/bin
+    install sommelier $out/bin
+  '';
+
+  meta = with lib; {
+    description = "Nested Wayland compositor with support for X11 forwarding";
+    maintainers = with maintainers; [ qyliss ];
+  };
+}
diff --git a/pkgs/os-specific/linux/chromium-os/update.py b/pkgs/os-specific/linux/chromium-os/update.py
new file mode 100755
index 00000000000..1405c534d8b
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/update.py
@@ -0,0 +1,115 @@
+#! /usr/bin/env nix-shell
+#! nix-shell -i python -p "python3.withPackages (ps: with ps; [ lxml ])"
+
+import base64
+import json
+import subprocess
+from codecs import iterdecode
+from os import scandir
+from os.path import dirname, splitext
+from lxml import etree
+from lxml.etree import HTMLParser
+from re import MULTILINE, fullmatch, match, search
+from urllib.request import urlopen
+
+# ChromiumOS components used in Nixpkgs
+components = [
+    'aosp/platform/external/modp_b64',
+    'chromiumos/overlays/chromiumos-overlay',
+    'chromiumos/platform/crosvm',
+    'chromiumos/platform/minigbm',
+    'chromiumos/platform2',
+    'chromiumos/third_party/adhd',
+    'chromiumos/third_party/kernel',
+    'chromiumos/third_party/libqmi',
+    'chromiumos/third_party/modemmanager-next',
+]
+
+git_root = 'https://chromium.googlesource.com/'
+manifest_versions = f'{git_root}chromiumos/manifest-versions'
+buildspecs_url = f'{manifest_versions}/+/refs/heads/master/full/buildspecs/'
+
+# CrOS version numbers look like this:
+# [<chrome-major-version>.]<tip-build>.<branch-build>.<branch-branch-build>
+#
+# As far as I can tell, branches are where internal Google
+# modifications are added to turn Chromium OS into Chrome OS, and
+# branch branches are used for fixes for specific devices.  So for
+# Chromium OS they will always be 0.  This is a best guess, and is not
+# documented.
+with urlopen('https://cros-updates-serving.appspot.com/') as resp:
+    document = etree.parse(resp, HTMLParser())
+
+    # bgcolor="lightgreen" is set on the most up-to-date version for
+    # each channel, so find a lightgreen cell in the "Stable" column.
+    (platform_version, chrome_version) = document.xpath("""
+        (//table[@id="cros-updates"]/tr/td[1 + count(
+            //table[@id="cros-updates"]/thead/tr[1]/th[text() = "Stable"]
+            /preceding-sibling::*)
+        ][@bgcolor="lightgreen"])[1]/text()
+    """)
+
+chrome_major_version = match(r'\d+', chrome_version)[0]
+chromeos_tip_build = match(r'\d+', platform_version)[0]
+
+# Find the most recent buildspec for the stable Chrome version and
+# Chromium OS build number.  Its branch build and branch branch build
+# numbers will (almost?) certainly be 0.  It will then end with an rc
+# number -- presumably these are release candidates, one of which
+# becomes the final release.  Presumably the one with the highest rc
+# number.
+with urlopen(f'{buildspecs_url}{chrome_major_version}/?format=TEXT') as resp:
+    listing = base64.decodebytes(resp.read()).decode('utf-8')
+    buildspecs = [(line.split('\t', 1)[1]) for line in listing.splitlines()]
+    buildspecs = [s for s in buildspecs if s.startswith(chromeos_tip_build)]
+    buildspecs.sort(reverse=True)
+    buildspec = splitext(buildspecs[0])[0]
+
+revisions = {}
+
+# Read the buildspec, and extract the git revisions for each component.
+with urlopen(f'{buildspecs_url}{chrome_major_version}/{buildspec}.xml?format=TEXT') as resp:
+    xml = base64.decodebytes(resp.read())
+    root = etree.fromstring(xml)
+    for project in root.findall('project'):
+        revisions[project.get('name')] = project.get('revision')
+
+# Initialize the data that will be output from this script.  Leave the
+# rc number in buildspec so nobody else is subject to the same level
+# of confusion I have been.
+data = {'version': f'{chrome_major_version}.{buildspec}', 'components': {}}
+
+paths = {}
+
+# Fill in the 'components' dictionary with the output from
+# nix-prefetch-git, which can be passed straight to fetchGit when
+# imported by Nix.
+for component in components:
+    name = component.split('/')[-1]
+    url = f'{git_root}{component}'
+    rev = revisions[component]
+    tarball = f'{url}/+archive/{rev}.tar.gz'
+    output = subprocess.check_output(['nix-prefetch-url', '--print-path', '--unpack', '--name', name, tarball])
+    (sha256, path) = output.decode('utf-8').splitlines()
+    paths[component] = path
+    data['components'][component] = {
+        'name': name,
+        'url': url,
+        'rev': rev,
+        'sha256': sha256,
+    }
+
+# Get the version number of the kernel.
+kernel = paths['chromiumos/third_party/kernel']
+makefile = open(f'{kernel}/Makefile').read()
+version = search(r'^VERSION = (.+)$', makefile, MULTILINE)[1]
+patchlevel = search(r'^PATCHLEVEL = (.*?)$', makefile, MULTILINE)[1]
+sublevel = search(r'^SUBLEVEL = (.*?)$', makefile, MULTILINE)[1]
+extra = search(r'^EXTRAVERSION =[ \t]*(.*?)$', makefile, MULTILINE)[1]
+full_ver = '.'.join(filter(None, [version, patchlevel, sublevel])) + extra
+data['components']['chromiumos/third_party/kernel']['version'] = full_ver
+
+# Finally, write the output.
+with open(dirname(__file__) + '/upstream-info.json', 'w') as out:
+    json.dump(data, out, indent=2)
+    out.write('\n')
diff --git a/pkgs/os-specific/linux/chromium-os/upstream-info.json b/pkgs/os-specific/linux/chromium-os/upstream-info.json
new file mode 100644
index 00000000000..5264a72a6c9
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/upstream-info.json
@@ -0,0 +1,60 @@
+{
+  "version": "81.12871.0.0-rc1",
+  "components": {
+    "aosp/platform/external/modp_b64": {
+      "name": "modp_b64",
+      "url": "https://chromium.googlesource.com/aosp/platform/external/modp_b64",
+      "rev": "ae26ad8516036774fd3b6e84a98a89955dcf5f61",
+      "sha256": "03ja5fkq3wk0qcnfnqcj09lciky6n6zdj544xs1jfssjhz9yj8hi"
+    },
+    "chromiumos/overlays/chromiumos-overlay": {
+      "name": "chromiumos-overlay",
+      "url": "https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay",
+      "rev": "be285b729ef2af700cc248f741af20c387b5a1bc",
+      "sha256": "18y2icdb3hxqxxaaz8sylw21q2qwcpjyns75ig7ahc4vc1k5hg7s"
+    },
+    "chromiumos/platform/crosvm": {
+      "name": "crosvm",
+      "url": "https://chromium.googlesource.com/chromiumos/platform/crosvm",
+      "rev": "8b8c01e1ad31718932491e4aee63f56109a138e2",
+      "sha256": "1qmf1k06pwynh15c3nr9m6v90z2pkk930xniwvlvbvnazrk4rllg"
+    },
+    "chromiumos/platform/minigbm": {
+      "name": "minigbm",
+      "url": "https://chromium.googlesource.com/chromiumos/platform/minigbm",
+      "rev": "fbfb338e7db246f05ae68da97141fbd49481584b",
+      "sha256": "11p6v4nmqivyqyc8lmypbwqv9q819lhx6v3igfsv3455mmq02kcb"
+    },
+    "chromiumos/platform2": {
+      "name": "platform2",
+      "url": "https://chromium.googlesource.com/chromiumos/platform2",
+      "rev": "6e0d88d0bea8e7cb28a310298cc8c77ed742f60a",
+      "sha256": "13vrbnl3ck8cxiyifc58cs9i0yby92vp5si27ihrx33v6bdlir4s"
+    },
+    "chromiumos/third_party/adhd": {
+      "name": "adhd",
+      "url": "https://chromium.googlesource.com/chromiumos/third_party/adhd",
+      "rev": "f361d5b02623274723bff251dafa1e2a2887b013",
+      "sha256": "1p8iwjwgmcgmzri03ik2jaid8l0ch0bzn6z9z64dix1hlrvrlliw"
+    },
+    "chromiumos/third_party/kernel": {
+      "name": "kernel",
+      "url": "https://chromium.googlesource.com/chromiumos/third_party/kernel",
+      "rev": "17611b6e636c8ccae25e873e659d69c20b215815",
+      "sha256": "0an8w3660v2zf2crb68ambg7vzw2rajpjmcby1am08qy37lqsfkd",
+      "version": "5.4.16"
+    },
+    "chromiumos/third_party/libqmi": {
+      "name": "libqmi",
+      "url": "https://chromium.googlesource.com/chromiumos/third_party/libqmi",
+      "rev": "6267c12fef0be9a95d687bf4b476593eeffbaaf1",
+      "sha256": "00yjjcngjkbgxmmf79ciddk9yq393a94230ahq8vszyfygzhs3rz"
+    },
+    "chromiumos/third_party/modemmanager-next": {
+      "name": "modemmanager-next",
+      "url": "https://chromium.googlesource.com/chromiumos/third_party/modemmanager-next",
+      "rev": "a4d3a4de1fdab7c282f1a188d2d3d0aaa24f0698",
+      "sha256": "1b1l1jfiyl7fnm29pp9npi0gdlqcw1jmmbigf0qlndqdh0ly2izg"
+    }
+  }
+}
diff --git a/pkgs/os-specific/linux/chromium-os/vm_protos/default.nix b/pkgs/os-specific/linux/chromium-os/vm_protos/default.nix
new file mode 100644
index 00000000000..5f40c5b416b
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/vm_protos/default.nix
@@ -0,0 +1,31 @@
+{ common-mk, lib, go-protobuf, grpc, openssl, protobuf }:
+
+common-mk {
+  pname = "vm_protos";
+  platformSubdir = "vm_tools/proto";
+
+  nativeBuildInputs = [ go-protobuf ];
+  buildInputs = [ grpc openssl protobuf ];
+
+  postPatch = ''
+    substituteInPlace common-mk/proto_library.gni \
+        --replace /usr/bin/grpc_cpp_plugin ${grpc}/bin/grpc_cpp_plugin
+  '';
+
+  installPhase = ''
+    mkdir -p $out/lib/pkgconfig
+    install -m 644 ../../vm_tools/proto/vm_protos.pc $out/lib/pkgconfig
+
+    headerPath=include/vm_protos/proto_bindings
+    mkdir -p $out/$headerPath
+    install -m 644 gen/$headerPath/*.h $out/$headerPath
+
+    install -m 644 *.a $out/lib
+  '';
+
+  meta = with lib; {
+    description = "Protobuf definitions for Chromium OS system VMs";
+    maintainers = with maintainers; [ qyliss ];
+    platform = platforms.all;
+  };
+}