Googlebook OS on a Dell Latitude 5300. Full 43 s demo: gbos86.com/static/demo.mp4
Google's Googlebook OS (the lapis Android desktop build) running on an ordinary laptop: a
Dell Latitude 5300 (Intel i5-8365U "Whiskey Lake", UHD 620, 16 GB). It boots from a USB stick or
from the internal NVMe/eMMC, reaches the desktop, and runs Play Store apps.
Website and community: https://gbos86.com (guides, hardware list, forum) | Discord: https://discord.gg/h9AD9fSnDT
usb/patched/andusb/libkm_compat.soare modified copies of Google's proprietary libraries, included because the build needs them; Google's terms apply to them. The OS images themselves are not in the repo (they are GBs and Google's); you rebuild them from Google's official recovery download. gbOS86 is an independent project, not affiliated with or endorsed by Google.
You need macOS or Linux with docker (running), python3, curl and about 35 GB of free disk. Nothing from Google is stored in this repository: the script downloads Google's public recovery image itself.
git clone https://github.com/linuxkid473/gbos-x86 && cd gbos-x86
./build.shWhen you run ./build.sh, it prompts you to select the image type:
- Host-tailored auto image: Auto-probes the host hardware (CPU, AVX2, GPU, display resolution and optimal UI density) and tailors
gbos.cfgautomatically. - Standard image (
dist/gbOS86-YYYYMMDD.img): Live USB installer. Boots into the gbOS86 boot menu (MODE=ask), allowing you to run live in RAM or install/update on the internal SSD. - Loopback persistent image (
dist/gbOS86-looper-YYYYMMDD.img): Portable standalone OS. Boots directly into Android (MODE=boot) with persistent ext4/metadataand/data. All installed apps, accounts, and settings persist directly on the USB stick.
You can also pass CLI arguments directly:
./build.sh --auto # Auto-detect host hardware and build a tailored image
./build.sh --standard # Standard installer image
./build.sh --looper --data-size 64 # 64 GB sparse userdata (only ~6.5 GB on host disk)Then flash the generated .img file from dist/:
# Flash with balenaEtcher, Rufus, or dd:
sudo dd if=dist/gbOS86-*.img of=/dev/rdiskN bs=4m status=progressBoot the laptop from the stick (F12 at the logo, Secure Boot off).
./build.sh --dry-run shows what it would download (Google's 7.7 GB image, ~1 MB busybox, 14 MB of kernel modules and 70 MB of firmware
from this repo's release). It streams only the six partitions it needs out of
Google's zip, so the 19 GB disk image inside is never unpacked. Allow 30 to 60 minutes, mostly the download. Twenty-one machines have been
tried (see Tested laptops); if you try another, please post its gbos/logs/boot-N/hwdetect.txt in an issue.
Fedora/RHEL with SELinux enforcing: the scripts add :z to the docker bind mounts of this repo's own folders automatically; don't disable SELinux.
| Works | Notes |
|---|---|
| Boot to desktop, setup, Google sign-in | From USB or internal NVMe/eMMC |
| Persistent data | NVMe/eMMC install or USB looper image: /data and /metadata are ext4 partitions |
| Wi-Fi | Intel 9560 (CNVi 8086:9df0) + linux-firmware |
| Bluetooth | Intel 9560 USB (8087:0aaa) via our btusb |
| Sound | Legacy HDA + Realtek ALC3254, speakers, headset jack, internal mic, HDMI |
| Touchpad with scrolling/gestures, keyboard | Intel LPSS I2C HID |
| Battery / AC | ACPI battery |
| Play Store installs | With the patched libcrypto (SHA-256 no longer emulated) |
| Screen-lock password | Software Gatekeeper (gatekeeper/soft_gk.c) |
| Root for apps (KernelSU) | Built into the kernel; the manager app is installed on first boot, root is granted per app in it |
| Correct display colours / black levels | Kernel #29: i915 ignores the HWC's gamma tables (see below) |
| Not done / limited | |
|---|---|
| Speed | Some instructions are still emulated in the kernel (see "Why it's slow") |
| Night Light | Gamma tables from userspace are ignored (that's the colour fix), so it has no effect |
| Linux Terminal (AVF) | Secretkeeper hang fixed; VM boot not yet confirmed |
| Auth-bound keystore keys | soft_gk's auth tokens aren't trusted by the software KeyMint |
| Google's on-device AI (Magic Pointer, AICore) | Google's servers refuse it without hardware key attestation, which no non-Google laptop can provide |
| OS updates | Built-in OTA can't work; moving to a new Google build is semi-automated: tools/port_build.sh, see porting.md |
| Other laptops | Eight of twenty-one tried machines work fully, ten partly, one pending, two not; see Tested laptops. The CPU-emulation kernel should help any pre-2021 Intel CPU |
UEFI firmware
└─ EFI/BOOT/BOOTX64.EFI our kernel (android17-6.18 + patches + KernelSU) with stage0 built in as initramfs
└─ stage0 (usb/stage0_init.sh, busybox)
├─ finds the gbos volume: USB stick (FAT label GBOS) or system volume (GBOSSYS)
├─ loads i915, logs to gbos/logs/boot-N/
├─ MODE=install → gbos/install.sh (NVMe/eMMC installer/updater), never boots Android
├─ mounts super.img's erofs partitions (system, vendor, product, ...) via loop + dm-linear
├─ runs gbos/hook.sh (all Android-side workarounds, editable without a kernel rebuild)
├─ mounts /data, /metadata (ext4 partitions if present, else tmpfs)
└─ switch_root → /system/bin/init selinux_setup (Google's Android init, unmodified)
The core problem: lapis binaries use CPU instructions this CPU lacks: GFNI, AVX-VNNI, SHA-NI, 256-bit VAES/VPCLMULQDQ, AVX-IFMA. Two layers deal with that:
-
Kernel emulation (
kernel/isa_emu_patch/). The#UD(invalid opcode) handler decodes the instruction, emulates it on the saved FPU state (isa_emu_core.c, 13k known-answer tests), and continues. It is correct but slow, about a microsecond per instruction. -
Binary patches for the hottest code (
usb/patched/, bind-mounted byhook.sh, and only applied when the original's sha256 matches):libz.so:adler32_zalways takes its scalar path (was ~50% of all emulation).libcrypto.so×3 (system, vendor, Conscrypt APEX): SHA-NI SHA-256 → scalar SHA-256 (was ~50%).
When they are bound.
usb/early_patch.sh(sourced fromgbos.cfg) wrapschrootin stage0 and binds the system/vendorlibz+libcryptojust before the firstdmctlcall. Without it, everydmctlprocess (one per partition) loads libcrypto and runs BoringSSL's load-time module hash through SHA-NI, about 3.7M emulated instructions, ~2 s of boot, beforehook.shcould bind anything.hook.shstill does the same binds later as a fail-safe and logsalready patched (early_patch.sh)when the early pass got there first. Both are gated on the sha256 of the exact original, so a new Google build silently disables them (NOT patchedinstage0-dmesg.txt; the hashes live inusb/patched/MANIFEST, regenerated bytools/port_build.sh, seeporting.md). To verify on hardware:stage0-dmesg.txtmust showearly: patched /new/system/lib64/libcrypto.sobeforerunning gbos/hook.sh. Shipping:early_patch.shis ininstall.sh'sFILES(so 1 Update copies it to the NVMe) and in the image builder. Thegbos.cfgsource line is guarded by[ -f ... ], so a stick without the file still boots.
Google hardware the laptop doesn't have, mostly the GSC security chip and the pKVM Trusty VM:
hook.sh hides or replaces each service that would otherwise hang the boot:
| Symptom | Cause | Fix (in usb/hook.sh unless noted) |
|---|---|---|
| "System process not responding" | LockSettings waits forever for Weaver (Trusty) | hide Weaver's VINTF declaration |
| Setup crashes ("Failed to create shared Bitmap") | no /dev/ashmem (Rust ashmem driver, RUST=n) |
kernel/ashmem_shim/ (C memfd ashmem ioctls) + sys.use_memfd=true |
| Setting a password hangs Settings | Trusty Gatekeeper never answers | gatekeeper/soft_gk.c software Gatekeeper |
| keystore2 aborts / KeyMint hangs | Trusty/StrongBox KeyMint need the GSC | patched libkm_compat.so (software KeyMint), StrongBox APEX hidden |
| Linux Terminal never starts its VM | Trusty Secretkeeper never answers | hide Secretkeeper's VINTF declaration |
| Logs truncated, stick corrupted | vold fsck_msdos'd the stick while mounted |
remove vold's voldmanaged=usb fstab rule |
| No sound | Google uses SOF; our kernel has legacy HDA | usb/audio/ config for the dras audio HAL (card id PCH) |
| White veil, lifted blacks (even video) | drm_hwcomposer loads its xe LOG_GAMMA_LUT curve into i915's linear GAMMA_LUT every frame |
kernel/isa_emu_patch/i915_ignore_gamma.sh (kernel #29) |
| Everything too big | ro.sf.lcd_density=260 for Google's panel |
RESOLUTION in gbos.cfg (default 2400x1350, stock density); DENSITY optional |
Laptop-specific drivers that Google's vendor modules can't provide (they're built for Google's kernel):
battery/AC, Intel LPSS I2C (touchpad), AMD pinctrl/GPIO (I2C touchpad interrupts), legacy HDA audio and
btusb are enabled in our kernel (kernel/configure_whl.py). Wi-Fi and Bluetooth firmware are in
usb/firmware/.
Root for apps (KernelSU). KernelSU is built into our kernel
(kernel/kernelsu/apply.sh puts the sources in drivers/kernelsu, CONFIG_KSU=y), so apps can be
given root the usual Android way: the manager app is installed on the first boot (from the stick,
usb/ksu/), and it decides which app may use su. Two things are worth knowing:
- The kernel only accepts a manager APK whose signing certificate is the official one
(827 bytes, sha256
c371061b…), so a Play Store copy of the app is not accepted: the APK comes from the KernelSU release (build.shputs it inusb/ksu/manager.apk). The daemon the kernel starts (/data/adb/ksud) is inusb/ksu/ksud(the x86_64 Android build). - Since Linux 6.9 x86 dispatches syscalls through a switch statement instead of the syscall table,
so patching the table (what KernelSU's hooks do) has no effect. KernelSU's own answer to that is
CONFIG_KSU_X86_PATCH_SYSCALL_DISPATCHER=y, which patches thex64_sys_calldispatcher at runtime; it is on inkernel/configure_whl.py. Nothing else in the kernel is changed, and SELinux stays permissive (KernelSU is built in, not loaded late, so it does not switch SELinux to enforcing).
HANDOFF.md is the chronological engineering log: every bug, its evidence and its fix. Read it before
changing anything.
Reports from people who booted the stick (2026-10-18). A row says what was reported, not what the newest build can do. The same list is on
gbos86.com/hardware; the source of truth is website/laptops.py.
| Laptop | CPU | Result | Works | Does not work / notes |
|---|---|---|---|---|
| Dell Latitude 5300 | Core i5-8365U, 16 GB | Works | Everything tested: Wi-Fi, Bluetooth, sound, touchpad, brightness, battery, install | Suspend. The maintainer's machine |
| Acer Aspire Lite AL15-52 | Core i5-1235U, 8 GB | Works | Wi-Fi, display, touchpad, keyboard, sound, brightness, camera, Bluetooth, SD card | Needed two firmware fixes (Realtek Wi-Fi; Intel AX201 Bluetooth name ibt-0040-1050.sfi), both in firmware v34+. Older sticks need a rebuild or an Update from a fresh stick |
| Lenovo ThinkPad T470 | Intel 7th gen | Works | Reported as working with no setup | Short report |
| Intel NUC8BEH (mini PC) | Core i3-8109U, 8 GB | Works (live) | Wi-Fi, Bluetooth, display and brightness (external monitor), keyboard (external), USB ports | Sound not tested. SATA M.2 SSD: install support for SATA disks added afterwards (QEMU-tested only, not yet tried on this NUC) |
| HP Envy 13-aq0xxx | Core i5-8265U, 8 GB | Works | Reported as working great, live and installed to the NVMe (kernel #32) | Per-device detail is in the forum thread |
| Dell Latitude 5300 2-in-1 | Core i7-8665U, 16 GB | Works | Wi-Fi, Bluetooth, sound, touchpad, backlight, display, touchscreen, hinge, webcam, pen, suspend | Auto-rotate (sensor driver added to the next kernel), mic-mute LED |
| Dell Latitude 5290 2-in-1 | Core i5 (model not given) | Works | Sound, once the speaker volume is raised | Short report: speakers were very quiet, Master Playback Volume 87 in gbos-hda-pch/mixer_paths.xml fixed it (shipped from 2026-10-26) |
| Lenovo ThinkPad T480 | Core i5-8350U, 16 GB | Works | Wi-Fi, Bluetooth, sound, touchpad, touchscreen, keyboard, brightness, display, webcam (installed) | Slow to wake; Wi-Fi needs a toggle after sleep |
| Dell Latitude 3380 | Core i5-7200U, 8 GB | Partly | Wi-Fi, sound, touchpad, keyboard, brightness, display, webcam (installed) | Bluetooth (Qualcomm 0cf3:e007: firmware loads, hci0 up, cause unknown; needs logcat.txt). Kernel #42 |
| HP OmniBook 7 | Core Ultra 5 225U, 16 GB | Partly | Touchpad, keyboard, brightness, display | Wi-Fi (Intel BE201). Sound, webcam, Bluetooth not tested |
| HP Pavilion Power 15 | Core i7-7700HQ + GTX 1050, 16 GB | Partly | Wi-Fi, Bluetooth, touchpad, brightness, display, webcam | Speakers (fixed in the next update: audio config picked the NVIDIA HDMI card); dock/DisplayLink and the NVIDIA GPU have no driver |
| Lenovo ThinkPad T14 Gen 2 | Core i5-1135G7, 32 GB | Partly | Wi-Fi, Bluetooth, touchpad, keyboard, brightness, display (installed) | Sound, microphone, webcam. Needs a full hwdetect.txt |
| Microsoft Surface Pro 4 | Core i5-6300U | Partly | Screen, keyboard, touchpad, brightness, microphones | Wi-Fi (Marvell 88W8897: driver added to the next kernel), Bluetooth, touchscreen, cameras |
| Dell Inspiron 7391 2-in-1 | Core i7-10510U, 8 GB | Partly | Wi-Fi, Bluetooth, touchpad, keyboard, brightness, display, webcam, touchscreen (installed to NVMe) | Sound. The reporter notes this laptop uses SOF audio firmware on regular Linux |
| Realme Book Slim (2021) | Core i5-1135G7, 8 GB | Partly | Wi-Fi, Bluetooth, touchpad, keyboard, brightness, display, webcam (live USB) | Sound. No hwdetect.txt yet |
| Fujitsu Arrows Tab V727 (tablet) | Core m3-7Y30, 8 GB | Partly | Wi-Fi (Intel 8265), Bluetooth, sound card detected (HDA Intel PCH); live USB on kernel #33, USB 2.0 | Tagged "mostly works"; what fails is not listed in the report |
| Dell XPS 16 (2026) | Intel Core Ultra | Partly | Boots and runs | Screen refresh rate, Wi-Fi, camera. A kernel option reportedly fixes the screen: try it with MODOPTS in gbos.cfg |
| Framework Laptop 13 Pro | Core Ultra 5 325 (Panther Lake), 16 GB | Fix pending | Boots | Black screen on sticks without the Panther Lake xe firmware (GuC); firmware v35 has it. Awaiting confirmation |
| Microsoft Surface Laptop 7 (Intel) | Core Ultra 7 266V (Lunar Lake), 16 GB | Partly | Wi-Fi, keyboard, battery, speakers, headset jack, touchpad, Bluetooth | Microphone, HDMI audio, camera, touchscreen, suspend. Needed extra kernel and boot-script work (section below) |
| ASUS X441NA | Celeron N3350 | Does not work | No AVX on this CPU: Google's init dies on its first instruction (kernel panic, exit code 4). Not fixable; newer sticks stop with a message | |
| HP 14-ne0013dx | Intel | Does not work | No logs yet |
Pattern: 2017 to 2022 business and mainstream laptops work with little setup (Wi-Fi, Bluetooth, touchpad, display, webcam). The common gap on 10th/11th-gen machines is sound (Inspiron 7391, Realme Book Slim), which on those uses the SOF driver; newer Core Ultra machines boot but hit missing firmware (xe)
or Wi-Fi 7 cards without a working driver and firmware pair. Missing firmware is listed in hwdetect.txt under "missing firmware".
To try a driver option on your own laptop, put e.g. MODOPTS="xe.enable_panel_replay=0" in gbos/gbos.cfg (modules only; see the file's comments).
The kernel (#31) builds drivers for most Intel-era laptops as modules, and boot detects what is present:
usb/hwdetect.sh(called byhook.sh) bind-mounts the stick's full module tree (gbos/modules/, depmod'ed for the running kernel) over/lib/modules, then does a udev-style coldplug: it reads every device's sysfsmodaliasandmodprobe -a's them, repeating until no new module loads (a loaded driver creates new devices).- The kernel's firmware loader is pointed at
gbos/firmware(a trimmed linux-firmware + sof-bin, ~300 MB). logs/boot-N/hwdetect.txtrecords DMI vendor/model, PCI/USB devices without a driver, input devices, network and Bluetooth interfaces, backlight, sound cards, rfkill, missing-firmware messages andlsmod. Send it back when something doesn't work.
| Area | Covered |
|---|---|
| CPU | Anything the ISA-emulation kernel handles: 4th gen (Haswell) and newer with AVX2 (CPUs lacking AVX2, such as Celeron/Pentium/Atom or Sandy/Ivy Bridge, halt at boot with a clear message, as AOSP's dynamic linker executes AVX2 instructions); the Googlebook OS needs instructions older CPUs lack, so it is emulated (slow on pre-2021 CPUs) |
| Graphics / display / brightness | i915 (Gen9 to Raptor Lake) + ACPI video/backlight; xe for newer parts (needs its own firmware, in firmware release v35; the colour/gamma fixes are i915-only). AMD Radeon (amdgpu): experimental, software rendering only (CPU-drawn, slow; see below; untested on hardware) |
| Wi-Fi | Intel (iwldvm: 7260/7265, iwlmvm: 8265 to AX211/BE200), Realtek rtw88/rtw89, MediaTek mt7921/7922/7925, Qualcomm ath10k/ath11k, Broadcom brcmfmac |
| Bluetooth | btusb with Intel/Realtek/MediaTek/Qualcomm/Broadcom, Intel PCIe BT |
| Sound | Legacy HDA with every common codec, or SOF (Intel DSP, DMIC, SoundWire); the kernel picks per machine (snd_intel_dspcfg). The audio HAL config is generated for the card that appears (hook.sh) |
| Touchpad / keyboard | Intel LPSS I2C-HID, ISH, PS/2 (Synaptics, ALPS, Elan, ...), Synaptics RMI4 |
| Hotkeys, fans, rfkill | Dell, HP, ThinkPad, IdeaPad, Asus, Acer, Samsung, MSI, Sony, Fujitsu, LG, Intel HID/VBTN |
| Other | SD card readers (Realtek, SDHCI), USB webcams (UVC), Ethernet (r8169, e1000e, igc, USB r8152 and friends) |
Honest limits. Twenty-one machines have been booted (below); anything not on that list is built and wired but untested on
hardware. Sound on SOF machines needs the codec's mixer controls to match the generated config (best effort);
suspend/resume, fingerprint readers, IPU6 cameras and NVIDIA/AMD discrete GPUs are not covered. Build the payload with
tools/fetch_firmware.sh (firmware, not committed) and kernel/isa_emu_patch/build_generic*.sh (modules, not committed).
Tested on a Surface Laptop for Business 7th Edition with Intel: boots from the stick to the desktop. What works and what it needed (the causes and the order they were found in are in HANDOFF.md, 2026-10-18):
| Works | Needs |
|---|---|
| Wi-Fi (BE201) | CONFIG_IWLMLD |
| Internal keyboard, battery/charger, fan, platform profile | Surface Aggregator: kernel/isa_emu_patch/surface_sl7_sam.sh, SERIAL_8250_RUNTIME_UARTS=4, PINCTRL_INTEL_PLATFORM (the last two in configure_whl.py --generic) |
| Speakers, headset jack | RT1320 amp + RT721 codec on SoundWire: python3 kernel/isa_emu_patch/sdw_sl7.py, firmware realtek/rt1320/ (tools/fetch_firmware.sh), usb/audio/mixer_paths_surface_laptop_7.xml |
| Touchpad with gestures and physical click | tools/build_surface_tools.sh (iptsd), usb/surface/ |
| Bluetooth | nothing extra |
| Touchscreen, suspend/resume | nothing beyond the rows above (tested by hand on the laptop) |
| Stable picture (no ghost images or freezes) | XE_PARAMS="enable_psr=0 enable_fbc=0" in gbos.cfg |
Not working: internal microphone, HDMI audio, camera. DEVICE_MODEL="Surface Laptop 7" in gbos.cfg shows
that name as Model / Device name in Settings. Tests: tools/test_audio_config.sh, tools/test_iptsd_run.sh, tools/test_device_model.sh.
Credit: nierdal's write-up and patches in linux-surface/linux-surface issue #1710 (SAM entry, SoundWire analysis, touchpad calibration and
LiftGraceMs), and alex-lentz's iptsd fork.
Google's image only has an Intel graphics driver (the Vulkan driver vulkan.intel.so, and a gralloc (minigbm) with no amdgpu backend), so on a Ryzen
laptop nothing could draw. When boot finds no Intel GPU and a non-Intel DRM driver bound (the kernel and firmware for amdgpu are already
shipped), hook.sh switches to software rendering, logged as hook: software rendering: ...:
usb/patched/vulkan.swiftshader.so(SwiftShader, a CPU Vulkan driver built for Android bytools/swiftshader-android/build.sh; fetched bybuild.shfrom the release, 24 MB) is bind-mounted over/vendor/lib64/hw/vulkan.intel.so, so ANGLE, Skia and SurfaceFlinger render on the CPU.usb/patched/libminigbm_gralloc.amdgpu.so(tools/patch_gralloc_amdgpu.py) is bind-mounted over/vendor/lib64/libminigbm_gralloc.so(Google's gralloc, minigbm built in): one of its identical generic linear dumb-buffer backends (the ARM-only "komeda" one) now answers to DRM driveramdgpu, so gralloc can allocate scanout/render buffers; and Google's "software renderer" flag (lets a CPU Vulkan driver lock buffers that were allocated for the GPU only) is switched on forro.hardware.vulkan=intel.libgbm.amdgpu.sodoes the same for/vendor/lib64/libgbm.so(only the camera and video-codec HALs use that one). Each is bound only over the exact original (sha256).- Background blur and overlay planes are turned off (
ro.surface_flinger.supports_background_blur=0,ro.vendor.hwc.use_overlay_planes=false): blur is far too slow on the CPU, and the composer's non-Intel backend is untested.
RADV (real GPU rendering, experimental). tools/radv-android/build.sh cross-builds Mesa main (b888682c)'s AMD Vulkan driver (RADV, no LLVM) for Android with the
NDK r30 in Docker (about 10 minutes after the downloads) and writes build/radv/vulkan.radv.so (18 MB; an Android Vulkan HAL: exports HMI, needs only
libcutils/liblog/libnativewindow/libsync/libz + bionic). Copy it to usb/patched/; with GPU_VULKAN=auto (default) hook.sh then binds it over
vulkan.intel.so instead of SwiftShader when amdgpu is bound (GPU_VULKAN=swiftshader goes back). It reaches the desktop on an
MSI Modern 15 B7M (Ryzen 5 7530U, Barcelo, RADV RENOIR), and video previews in Play Store and Photos play. Known problems on that machine: Photos cannot open
HEVC clips (the software HEVC decoder fails), the pointer renders as a red square, and the built-in touchpad is absent; AMD pinctrl/GPIO is now enabled in the generic kernel profile, but that touchpad change still needs hardware verification. See HANDOFF.md.
tools/test_gpu_select.sh tests only the driver-selection logic.
GPU_SOFTWARE in gbos.cfg: auto (default; never changes anything while an Intel GPU is present), 1 (force, for testing on Intel), 0 (never).
Expect a working desktop; use a lower RESOLUTION if it crawls. The AMD CPU side (Ryzen) has been tested on one MSI Modern 15 B7M (Ryzen 5 7530U).
tools/test_gpu_select.sh tests the decision logic and tools/swiftshader-android/qemu/run.py smoke-tests the
driver inside Google's userspace under QEMU.
| Path | What |
|---|---|
usb/stage0_init.sh |
stage0: volume detection, logging, partition mounts, switch_root |
usb/hook.sh |
Android workarounds, run by stage0 before switch_root; writes gbos.rc (init services) |
usb/early_patch.sh |
Sourced from gbos.cfg; binds the patched libz/libcrypto before stage0's first dmctl |
usb/install.sh |
NVMe/eMMC/SATA installer and updater (MODE=install) |
usb/apex_patch.sh |
binds the patched libcrypto over the APEX copies (run from init.rc) |
usb/gbos.cfg |
user settings: MODE (ask/live/install/boot), DENSITY, RESOLUTION, LOAD_I915, ... |
tools/make_gbos86_image.sh |
builds the flashable gbOS86 USB image into dist/ |
usb/audio/ |
audio HAL config for the HDA card |
usb/ksu/ |
KernelSU's manager app and daemon (installed on the stick by build.sh) |
usb/out/BOOTX64.EFI |
current kernel (build #30: #29 + gbOS86 boot menu), boots directly from UEFI |
usb/patched/, usb/libkm_compat.so |
patched Google libraries; usb/patched/MANIFEST (generated) lists each patch with the sha256 of its original |
tools/swiftshader-android/ |
builds SwiftShader as Android's Vulkan HAL (docker + NDK) for AMD GPUs |
usb/kmod/ |
btusb, btintel, btrtl built for kernel #29 |
usb/installer/ |
Alpine sfdisk/mke2fs/e2fsck/mkfs.fat/blkid + musl (tools/fetch_installer_tools.sh) |
usb/a11y/ |
stage0 screen reader: start.sh/stop.sh + espeakup, espeak-ng (English), amixer (tools/fetch_a11y_tools.sh) |
usb/firmware/ |
Intel Wi-Fi + Bluetooth firmware, regulatory.db |
usb/soft_gk, gatekeeper/ |
software Gatekeeper binary and source |
usb/make_super.py, make_bootdisk.py, make_initramfs.py |
build super.img, the fake ChromeOS boot disk, the stage0 initramfs |
kernel/configure_whl.py |
kernel config for this laptop (from Google's recovery kernel config) |
kernel/fetch_kernel_sources.sh |
fetches the kernel tree, the AOSP clang and KernelSU into the gbos-ksrc volume |
kernel/kernelsu/apply.sh |
builds KernelSU into the kernel (drivers/kernelsu, CONFIG_KSU=y) |
kernel/isa_emu_patch/ |
instruction emulator + apply.sh/build.sh, debug_cmdline.txt |
kernel/build_kernel.sh |
builds the whole kernel (patches, config, modules, initramfs) in the gbos-kbuild container |
kernel/stage0_modules.txt |
the modules the stage0 initramfs carries (see kernel/make_stage0_initramfs.sh) |
kernel/ashmem_shim/ |
C memfd ashmem shim |
kernel/isa_emu_test/ |
QEMU tests: the emulator (16 instructions), run_isa_qemu.py and run_ksu_qemu.py (KernelSU in the kernel), hwdetect, run_installer_emmc.py (installer on an emulated eMMC) and run_installer_sata.py (on emulated SATA disks) |
isa-emu/ |
emulator core + host known-answer tests |
tools/ |
image extraction (lp_extract.py), ISA scanner (isa_scan.py), binary patchers, and the new-build porting tools (port_build.sh, check_new_build.sh, see porting.md) |
lapis/BUILD |
the Google build this repo is ported to (id, version, download URL) |
lapis/ |
download script, ISA scan results, QEMU userspace harness |
- p1 (
EFI): 256 MiB FAT32 ESP. - p2 (
GBOS): 6 GiB FAT32 (super.img, installer, patches). Booting shows the gbOS86 boot menu with a 10-second timeout: - 1) Live from USB (runs purely in RAM/tmpfs; nothing saved).
- 2) Install or update on internal SSD (erases the internal disk and installs gbOS86).
- 3) Boot the installed system (offered and default when an internal install exists).
Creates a full portable install directly inside the flash drive image, matching the internal disk layout:
- p1 (
GBOS_EFI): 512 MiB FAT32 ESP. - p2 (
GBOSSYS): 8 GiB FAT32 (super.img, firmware, modules,MODE=boot). - p3 (
GBOS_META): 64 MiB ext4 (/metadata). - p4 (
GBOS_DATA): User-configured capacity (e.g. 64 GiB) ext4 (/data).
Sparse capacity on host vs physical drive size: On the host file system, the image is created as a sparse file: a 64 GB userdata partition only occupies ~150 MB of ext4 metadata on disk, so the whole
.imgfile is only ~6.5 GB physically. However, when writing directly to a physical USB drive (dd), the drive must be large enough to hold all partitions. Choose--data-sizeto match your stick:
- 16 GB stick:
--data-size 6- 32 GB stick:
--data-size 20- 64 GB+ stick:
--data-size 64(default)
Boot the stick and select option 2 ("Install or update gbOS86 on this laptop's internal SSD"), or set MODE=install in gbos/gbos.cfg.
The target is the internal NVMe or eMMC disk (an eMMC is recognised by its MMC device type: SD cards, card readers and the stick are never targets; the eMMC's boot/RPMB areas are left alone). With more than one internal disk the installer refuses until INSTALL_DISK=nvme0n1 (or mmcblk0) is set in gbos.cfg.
A SATA disk (M.2 SATA or 2.5") is a target when the machine has no NVMe/eMMC: it is recognised by being owned by the SATA driver (libata), so a USB stick, a USB-SATA adapter or a card reader is never a target. A laptop with an NVMe and a SATA disk keeps installing to the NVMe; to use the SATA disk set INSTALL_DISK=sda in gbos.cfg.
The BIOS must show the disk in AHCI mode (not Intel RST/RAID or VMD), otherwise Linux cannot see it. (On a Dell the setting is SATA/NVMe Operation: change RAID On to AHCI/NVMe. CONFIG_VMD is not in this kernel.)
Minimum disk size 24 GB. eMMC controllers on the PCI bus work (sdhci-pci); ACPI-only ones (some AMD and older Atom parts) are not supported.
When installing onto a drive with existing operating systems (Windows or Linux), the installer offers an interactive choice:
-
1) Dual-Boot (Recommended — alongside Windows or Linux):
[!IMPORTANT] Unallocated Free Space Required: Dual-boot requires unallocated (unpartitioned) space on the target disk (at least 20–24 GB recommended; 8 GB for the
GBOSSYSsystem partition + remaining space forGBOS_DATAuserdata).- Windows: Open Disk Management (
diskmgmt.msc), right-click yourC:partition, select Shrink Volume, and specify at least24000MB (24 GB) to leave as unallocated space. - Linux: Use GParted or
partedto shrink an existing partition and leave unallocated space at the end of the disk.
The installer preserves all existing OS partitions and the shared EFI system partition. It creates
GBOSSYS(8 GB FAT32) andGBOS_DATA(ext4) within the unallocated space.- Linux / GRUB: Automatically adds
Googlebook OS (gbOS86)to your GRUB menu (viacustom.cfg) without menu duplicates. - Windows Boot Manager: The installer copies
Add-gbOS-to-Windows-BootMenu.batinto the EFI partition (\EFI\gbos86\); simply right-click and run it as Administrator in Windows to add gbOS86 to the Windows boot menu.
- Windows: Open Disk Management (
-
2) Full clean install (Erases entire disk): Lays out the entire disk cleanly:
GBOS_EFI512M (ESP),GBOSSYS8G FAT32 (system),GBOS_META64M ext4, andGBOS_DATA(remaining space for user apps/data). To prevent accidental data loss, it requires confirming by typing the drive's serial number. -
3) Start Live Desktop: Configures a one-time live session in RAM without writing to the disk.
-
If gbOS is already installed: The installer offers 1) Update (keeps your apps and data, updates system files and kernel), 2) Reinstall (clean wipe), or 3) Only save logs.
During installation, live progress bars indicate system image and driver/firmware copying, followed by fast sha256 verification.
- Boot menu and installer are spoken (kernel #46 and newer). The kernel has Speakup built in;
usb/a11y/on the stick holdsespeakup+espeak-ng(English) +amixer(about 10 MB, from Alpine, filled bytools/fetch_a11y_tools.sh). Stage0 copies it to RAM, unmutes the laptop's sound card, starts the reader and reads the boot menu and every installer message aloud; typed characters are echoed. The boot menu waits 60 s instead of 15 (A11Y_MENU_TIMEOUT), progress is announced every 10 percent, and the drive serial you must type before an erase is also spelled out character by character. The confirmation itself is unchanged.A11Y=0ingbos.cfgturns it off. Works on laptops whose sound card the kernel brings up by itself (legacy Intel HDA: most pre-2021 laptops), and on newer Intel ones whose HDA controller waits for the GPU driver (Raptor Lake:start.shloads i915/xe itself first). SOF-only machines have no sound at that stage, so no speech there (logged asa11y: no sound card). Nothing is spoken before the stick's kernel starts (the firmware's own boot-device menu is outside gbOS86). Test:kernel/isa_emu_test/run_a11y_qemu.py usb/out/BOOTX64.EFI(emulated Intel HDA, records the audio). - Android: set
ACCESSIBILITY=talkbackingbos.cfgand Google's TalkBack (already in the image, with Google TTS) is switched on at the first boot.
The system writes logs to its own GBOSSYS (or GBOS) partition. To read them, boot the stick, choose
menu 2, then 3 (Only save its logs) (or 1 to update too), and read gbos/logs/boot-N/nvme-logs/ on the stick from a computer. Each boot dir has
kmsg.log, stage0-dmesg.txt, rotated logcat.txt*, crash.txt, hw.txt, audio.txt, and pstore-prev/.
FAT has no journal: always shut down from Android's power menu, not the physical power button.
Density stays Google's stock 260. RESOLUTION=2400x1350 in gbos.cfg makes Android render at a larger
logical size that the display scales to the 1920x1080 panel: bigger = smaller UI (empty = native).
DENSITY= can still override the density but is unset by default. If you changed Settings → Display →
Display size, reset it to Default.
Needs macOS or Linux with docker, python3, qemu (for tests) and ~30 GB free. The build images used:
gbos-kbuild (kernel/docker/Dockerfile) and gbos-erofs (tools/erofs-docker/Dockerfile).
- Google's OS image:
lapis/dl.shdownloadslapis-user/16658739/recovery.zipfromdl.google.com. Extract the recovery disk image from it, then pull the logical partitions (system, vendor, product, system_ext, system_dlkm, vendor_dlkm; slot_a) out ofsuperwithtools/lp_extract.py DISK.raw lapis/parts NAME...(run it with justDISK.rawto list the names). super.img:usb/make_super.py OUT/super.img OUT/super.layout system_a=... vendor_a=...(system_a first). It must stay under 4 GB (FAT32).- Kernel source: AOSP
kernel/common, branchandroid17-6.18, commit3938c8d97142d5cf31543aa96f864a2cf832dda0, and the AOSP clang prebuilt.kernel/fetch_kernel_sources.shfetches all of it into the docker volumegbos-ksrc(/build/{src,inputs,out}): the kernel tree,clang-r584948b(LLVM 22.0.1, the toolchain the shipped kernel was built with; the AOSP prebuilts repo publishes thebbuild of that clang, not thecone) and the KernelSU sources (/build/inputs/KernelSU, tag v3.3.1). - Config:
kernel/configure_whl.py RECOVERY_KERNEL.config /build/out/.config, thenmake olddefconfig; setCONFIG_CMDLINEfromkernel/isa_emu_patch/debug_cmdline.txt(debug_config.sh) andCONFIG_INITRAMFS_SOURCE=/build/out/gbos_stage0.cpio. - Patches: in the volume,
kernel/isa_emu_patch/apply.sh,kernel/ashmem_shim/apply.sh, and the i915 scriptskernel/isa_emu_patch/i915_color_pipeline.sh(dummy plane COLOR_PIPELINE for the HWC) andi915_edp_colorspace.sh(eDP always gets default colorimetry; BT.2020 made the panel pale) andi915_edp_no_colorspace.sh(no Colorspace property on eDP at all, from kernel #25) andi915_edp_full_range.sh(eDP always full-range RGB, from kernel #27) andi915_ignore_gamma.sh(ignore userspace gamma/degamma/CTM: the HWC loads an xe LOG_GAMMA_LUT curve into GAMMA_LUT, kernel #29), andkernel/isa_emu_patch/debug_selinux.sh(thegbos_permissiveparameter of the kernel command line: without it the kernel is not permissive, Android's init enforces SELinux and the boot stops right after "init: Loading SELinux policy"). For the Surface Laptop 7 (Intel) alsokernel/isa_emu_patch/surface_sl7_sam.shandpython3 kernel/isa_emu_patch/sdw_sl7.py(see HANDOFF.md); both only touch modules. Andkernel/kernelsu/apply.sh, which copies KernelSU's kernel sources intodrivers/kernelsuand hooks them intodrivers/Makefileanddrivers/Kconfig(CONFIG_KSU=y,CONFIG_KSU_X86_PATCH_SYSCALL_DISPATCHER=ycome fromkernel/configure_whl.py). - Build:
kernel/isa_emu_patch/build.sh(ingbos-kbuild), thenmake modules_installintousb/modroot, thenusb/make_initramfs.py usb/modroot usb/stage0.cpio, copy it to/build/out/gbos_stage0.cpio, and build again so it's embedded.arch/x86/boot/bzImageisBOOTX64.EFI.btusb.ko/btintel.ko/btrtl.kofrom/build/out/drivers/bluetooth/go inusb/kmod/. - Test the emulator:
kernel/isa_emu_test/run_isa_qemu.py usb/out/BOOTX64.EFI(expects 16/16 PASS), andkernel/isa_emu_test/run_ksu_qemu.py usb/out/BOOTX64.EFI(expects KSU_QEMU_TEST_PASS: KernelSU came up, its version is one the manager app accepts, and the x86_64 syscall dispatcher was patched). - Userspace pieces:
tools/fetch_installer_tools.sh;gatekeeper/build.sh(needsgatekeeper/libs/from the image:libc,libdlfrom the runtime APEX,libbinder_ndk,libcrypto,liblog); patched libraries withtools/patch_libz_adler.pyandtools/sha_redirect.py. The hashes inhook.sh/apex_patch.shpin the exact originals they apply to. KernelSU's manager app and daemon come from the KernelSU release (build.shputs them inusb/ksu/). - Firmware: from linux-firmware (
intel/iwlwifi/iwlwifi-9000-pu-b0-jf-b0-46.ucode,intel/ibt-17-16-1.{sfi,ddc});regulatory.db*from the vendor image.
Android's built-in updater can't work here (it expects Google's A/B partitions and kernel). Moving to a newer lapis build is
mostly automated; porting.md is the full procedure:
tools/check_new_build.shsays whether a newer build exists; put it inlapis/BUILDand run./build.shto fetch it;tools/port_build.sh --isare-applies every binary substitution (libz, libcrypto, libkm_compat, the VINTF manifest) to the new files, writesusb/patched/MANIFESTwith the sha256 of each original, checks every path/line/property the boot scripts rely on, and scans for instructions the emulator doesn't cover (add--writeonce it reports 0 FAIL);sh tools/test_port_scripts.shruns the scripts' patch-binding logic under the stick's busybox;- copy to the stick and run 1 (Update);
PATCH-STATUS N applied, 0 not appliedinstage0-dmesg.txtconfirms the patches bound. Data carries over; going back to an older build requires a data wipe.
- Full clean install erases the entire internal disk (NVMe, eMMC or SATA); typing the serial number is required. Dual-boot mode preserves existing OS partitions and only writes into unallocated free space.
- SELinux runs permissive, and the security services are software stand-ins. Don't treat this as a secure device.
- The ISA emulator runs in the kernel's
#UDhandler; a bug there is a kernel bug.

