Skip to content

gweslab/cerf

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

797 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Caution

CERF v1 IS DEPRECATED — no further development.

Why v1 was abandoned. v1 reimplemented Windows CE's userspace and kernel in host C++ — coredll exports thunked through to Win32, gwes.exe rehosted on host GDI/USER, kernel objects mapped onto host kernel handles. That approach hit a hard architectural ceiling: a single host process cannot hold the resources of an entire guest OS. Per-process Win32 limits (GDI handle table, atom table, kernel handle table, address space) saturate long before a real CE workload settles, because v1 mocked CE at the user-API layer — above CE's own per-process isolation — instead of below it, forcing every guest process to share one host process's quotas. The codebase was also overengineering hell that grew exponentially: every new app surfaced a new untested API path that demanded another thunk, another fake handle type, another quirk in the rehosted GWES. There is no incremental path from v1 to something that works.

Important

CERF v2 is in active development. v2 is a completely different project: a virtual ARM hardware platform that boots unmodified ROM binaries (kernel + OAL + drivers + userspace) on x64 Windows. Instead of thunking CE APIs, v2 emulates the SoC silicon — DRAM, MMU, interrupt controller, GPIO, UART, LCD, timers, ADC — and runs the device's own nk.exe, coredll.dll, gwes.exe, filesys.exe, device.exe and driver DLLs as their original ARM machine code through a JIT. Per-SoC strategies make it universal: one emulator is designed to target S3C2410, PXA, OMAP, SA-1110, Poseidon and more, across every CE generation from Pocket PC 2000 / Windows CE 3 through Windows Mobile 6.x and Windows CE 7 — including platforms that have no other working ARM emulator today.

Ambitions on the v2 roadmap: universal SoC coverage (SMDK2410 / OMAP3530 / Poseidon / SA-1110, possibly Zune and Windows Phone hardware later), CERF-exclusive guest-side features (guest additions maybe?)

v2 will be published only once it runs well. When the first SoC reliably boots a full ROM to a usable shell, the v2 repository will appear publicly. Until then, this v1 tree is here for historical reference only.


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