Skip to content

gweslab/cerf

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

794 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CERF — Windows CE Runtime Foundation

Boot real Windows CE and Windows Mobile ROMs on modern x64 Windows. Run unmodified ARM PE binaries — shells, drivers, apps — with the original operating system brought up around them.

Warning

Early stage. Most things don't work yet. Expect crashes, missing APIs, and broken apps. Treat CERF as an experiment, not a usable emulator.

Successor to wcecl.

What CERF is

A full Windows CE system emulator. Under the hood: an ARM CPU emulator, a reimplementation of the CE kernel and its process/MMU model, and a rehosted windowing subsystem — wired together so real ROM binaries boot end-to-end on top of host Windows.

The entire CE backend — the kernel-mode side plus the system services that coredll.dll, gwes.exe, and device.exe sit on — is reimplemented inside cerf.exe. Init sequence, registry, filesystem, handle table, process/MMU model, driver host: all of it lives in CERF. Unmodified ROM binaries — shells, drivers, apps — run on top exactly as they would on a real device. Windowing and driver-facing surfaces ultimately reach host Win32 primitives, but the CE semantics that sit on those primitives live in CERF itself.

Highlights

  • ARM CPU emulator (block JIT). Every .exe and .dll on the device runs as its original ARM machine code, translated to x64 on the fly by dynarmic.
  • Full gwes.exe replacement. The Graphics/Windowing/Events Subsystem is rehosted on native Win32. Host Win32 windows, messages, and input are bridged back into ARM WNDPROCs through a callback executor — the guest sees real CE gwes; the host sees a well-behaved Win32 app.
  • Pixel-accurate control rendering and theming. Button, Static, Edit, ListBox, ScrollBar, Dialog, and Menu ship as native fallback WNDPROCs that mirror CE5 gwes down to default-message handling and owner-draw quirks. CE themes render. Renderers are strategies; swapping in a Windows Mobile look or a custom theme is a matter of registering another one.
  • Kernel, process, and MMU emulation. Per-process 32 MB ProcessSlot overlays replicate CE's slot-based address space. Multiple CE kernel versions are supported via pluggable strategies — CE5 and CE6 ship different PSL dispatchers, different TCP-stack plumbing, different shell-folder lookups. More can be added the same way.
  • PSL (Protected Server Library) cross-process dispatch. When an app calls into a driver, CERF switches address spaces, marshals pointer arguments between caller and callee slots, and runs the handler — exactly as real CE does. Nested MapCallerPtr works.
  • device.exe mock as a real driver host. ARM driver DLLs (AFD, tcpstk, and friends) load into an emulated driver process with its own slot. DeviceIoControl fans out through PSL with correct slot switching.
  • Hardware-layer thunks with access levels. Calls that would normally talk to silicon are intercepted at the kernel/COREDLL boundary, with privilege and access enforced inside the thunks themselves rather than faked at a higher layer.
  • DLL loader that behaves like kern.exe. Loads ARM PEs into emulated memory, patches IATs, runs per-process DllMain, tracks module refcounts via per-DLL bitmasks the way real CE does.
  • Emulated registry, virtual filesystem, handle table, critical sections, thread registry. Enough real kernel state for a real boot.
  • Init hive boot sequence. Processes come up from HKLM\init in dependency order, the same way filesys.exe brings up a real device.
  • OOP rewrite (in progress, almost done). No globals, no statics — every subsystem lives on a CerfEmulator instance and is resolved through a service locator. The payoff: two CerfEmulators inside one cerf.exe share nothing and can boot different devices side by side.

Supported device profiles

Device behaviour is selected at boot from a profile under bundled/devices/<name>/ — a directory containing the ROM filesystem, registry hive, and a device-specific cerf.ini. The .ini picks named strategies for subsystems that differ between CE versions:

psl_dispatch   = ce5_psl  | ce6_psl
sh_thunk       = ce5      | wm5_psl

Adding a new device is a config-and-assets drop — no code changes are needed when the strategies it requires already exist.

Profile Status
wince5 Largely supported; the primary development target. IE works. Many APIs still missing. MMU and process isolation may have bugs.
wm5 Bootable. WIP. Anything past the today screen is broken. Expected to reach CE5-level stability over time since both share the same base OS. Reconstructed from a B000FF baked-memory ROM via extract-wince-rom into regular PE files with IATs.
wince6 Bootable without drivers. Needs its own PSL/MMU/isolation strategy (the CE7 strategy is likely a drop-in fit). Only basic apps are expected to work at present.
wince7 Bootable without drivers. Needs its own PSL/MMU/isolation strategy. Only basic apps are expected to work at present. Boots with the gwe_api_sets_ce7_service.cpp workaround enabled.

Usage

cerf.exe                   # Boot default device (WinCE 5 desktop)
cerf.exe --device=wm5      # Boot Windows Mobile 5
cerf.exe --device=wince6   # Boot WinCE 6.0
cerf.exe --device=wince7   # Boot WinCE 7.0
cerf.exe --flush-outputs   # Force-flush logs (avoid truncation on crash)

Logs are written to cerf.log by default. On a fatal crash, register state and a top-of-stack snapshot for every other thread is dumped to cerf.crash.log next to it through a lock-free emergency writer (no ucrt, no mutexes) — useful when the reader thread crashes but a different thread is the actual writer. Run cerf.exe --help for the full CLI.

Tip

For fastest runtime, pass --log=none (or at minimum --no-log=trace). CERF ships with every log category on by default because the project is early-stage and logs are the primary debugging tool — every category on the hot path writes to cerf.log through a serialized critical section, which dominates a real workload. Disabling logging is the main per-run performance lever; turn it back on (or narrow it to --log=EMU,API,...) when diagnosing a crash or investigating behaviour.

Building

Requires Visual Studio 2022 or 2026 with the C++ desktop development workload.

Note

First build on a fresh machine takes 1+ hour. libslirp, glib, and their transitive dependencies are compiled from source by vcpkg before CERF itself starts linking. This happens once per machine — subsequent builds reuse the cached vcpkg_installed/ tree and finish in a few minutes. Do not interrupt the first build assuming it's stuck; watch the msbuild output for vcpkg restore progress.

Initialise submodules:

git submodule update --init --recursive

Build via the helper script (preferred — locates MSBuild via vswhere, kills stale build processes, and reports the produced binary):

powershell -ExecutionPolicy Bypass -File build.ps1

Or invoke msbuild directly:

msbuild cerf.sln /p:Configuration=Release /p:Platform=x64

Tests

Unit and integration tests use gtest and live under tests/, grouped by subsystem (e.g. tests/mmu/). They build into a single cerf_tests.exe alongside cerf.exe:

build/Release/x64/cerf_tests.exe

Tests share one in-process CerfEmulator brought up with --ephemeral-registry --disable-network, so the suite runs in well under a second and does not touch the device tree.

E2E tests

python e2e_tests/run_all.py

Each test writes its own log file; see the test sources for paths.

Extending

Each device profile lives in bundled/devices/<name>/. To target a new platform build, drop in the ROM filesystem and registry hive, write a cerf.ini that picks the matching strategies, and boot. Strategies self-register into the service locator and are selected by name from cerf.ini, so adding one touches no existing files. The sh_thunk subsystem (cerf/coredll/sh_thunks_ce5_service.cpp, cerf/coredll/sh_thunks_wm5_service.cpp) is the reference example to follow when implementing a new strategy.

Documentation

No formal docs yet. Start with CLAUDE.md and agent_docs/subsystems.md.

Third-party

CERF depends on two external runtime libraries:

  • dynarmic — ARM → x64 JIT that executes the guest's machine code. CERF tracks its own fork of azahar-emu/dynarmic.
  • libslirp — user-mode TCP/IP stack behind the virtual NDIS miniport (DHCP, DNS, TCP, UDP, IPv4, IPv6 via SLAAC). No admin or driver install required; pulled in automatically via vcpkg on first build.

Roadmap

CERF is an experimental project. Active development is expected to wind down once these milestones are reached:

  • Windows Mobile 5 boots and is usable.
  • Networking works in CE5 and WM5, ideally across the other device profiles too.
  • DOOM runs.

AI-generated code

The entire codebase was generated by Claude via Claude Code with no human-written code. It is not production-grade: there are likely bugs, shortcuts, and possibly fundamental issues in the emulation layers. Style and patterns also drift between files at this scale, with load-bearing invariants that live in prompts rather than asserts — debugging is rougher than a human-written codebase of comparable size. The project is nonetheless held to emulator-grade quality standards: faithful CE behaviour is the point, not a tech demo. The work began as an experiment in what Claude can produce in a real systems-programming setting and as a way to revive the wcecl concept end-to-end.

Downloads

build

Releases

No releases published

Sponsor this project

Packages

 
 
 

Contributors