Recovering a Biesse Rover 27 NC1000 boot DOM

A field note about reviving a LynxOS CNC controller with a failing IDE DOM, a patched CNi filesystem, a CompactFlash card, and a lot of stubborn debugging.

Sat Apr 25 2026 00:00:00 GMT+0000 (Coordinated Universal Time)

This started with a woodworking CNC that would not boot.

The machine was a Biesse Rover 27, controlled by a CNi NC1000 box running LynxOS. Its storage was not a normal hard disk, but a small IDE Disk-on-Module: a 256 MB flash module plugged into the controller motherboard. One morning it stopped with the kind of message that makes old industrial systems feel less like computers and more like archaeology:

Old-style boot block found.
No filesystem found on device
can't boot, unknown file system

On another boot it changed to:

Cannot open device h0a

That changing error was the first clue. A normal corrupted filesystem tends to fail the same way. A dying flash module often fails differently after each cold boot, because its controller is still returning sectors, just not always the same sectors.

I worked through this with AI heavily involved, especially Opus 4.7 and GPT-5.5. This was not a “ask once, paste command” situation. It was an iterative lab session: hex dumps, false theories, bootloader archaeology, image patching, and finally a stupidly simple hardware twist.

The first clone

The original DOM was cloned with ddrescue. The log looked perfect:

0x00000000  0x0F480000  +

No read errors. The image was exactly 256,376,832 bytes, or 500,736 sectors.

That was reassuring, but it was not proof the data was good. Flash can fail silently: the controller may happily return bytes that are already wrong. A clone with zero read errors can still be a clone of corrupted data.

The raw strings were extremely useful. They showed this was not random garbage. The image contained real boot files and configuration:

hdboot0.o
init
lynx.os-300
ubsv
gzip
CNCONF
preboot-300
FSYS.gz
FSYS1.gz

The network configuration also survived:

CN_HOST_NAME=cnc
CN_IP_ADDR=193.70.252.150
FSERV_HOST_NAME=vdcnc
FSERV_IP_ADDR=193.70.252.151
FSERV_EXPORT=/c/CN

This explained the architecture. The DOM does not contain the whole CNC application. It boots LynxOS, brings up the network, and mounts vdcnc:/c/CN from the Windows frontend PC. The user interface and machine software live there.

The DOM is the bootstrapper. Without it, the machine cannot reach the software that is still safe on the Windows PC.

The CNi boot chain

The first sector had a valid x86 boot signature and one active partition:

MBR signature: 55 aa
Partition type: 0x40
Start LBA: 32
Size: 496096 sectors

Inside that partition was not FAT, ext2, or anything modern. It was a small CNi filesystem used by preboot-300. The chain looked like this:

BIOS -> hdboot0 -> preboot-300 -> lynx.os-300 -> ubsv -> FSYS.gz -> LynxOS userspace

FSYS.gz and FSYS1.gz are the primary and backup gzipped root filesystems. ubsv exposes them as virtual block devices (/dev/zd0, /dev/zd1, and so on). After that, the boot script configures Ethernet and mounts the Windows NFS export.

This is why the machine could fail early with messages like Unknown File System even though the actual XNC application on the Windows PC was fine.

CompactFlash, CHS, and the first real patch

The replacement media on hand was a 4 GB Verbatim CompactFlash card in a CF-to-IDE adapter. The Athlon 64 test PC detected it as:

7745 cylinders
16 heads
63 sectors

The original 256 MB DOM, however, had partition table CHS values that only made sense with 16 heads and 32 sectors per track.

The original partition entry at byte 0x1BE was:

80 01 01 00 40 0F E0 C8 20 00 00 00 E0 91 07 00

Decoded:

active:       0x80
start CHS:    head=1, sector=1, cylinder=0
type:         0x40
end CHS:      head=15, sector=32, cylinder=968
start LBA:    32
sector count: 496096

Under the DOM geometry, CHS 0/1/1 means LBA 32. Under the CF geometry, CHS 0/1/1 means LBA 63. Same bytes, different physical sector.

So the first patch was simply to rewrite the CHS fields while preserving the LBA fields:

80 00 21 00 40 03 43 EC 20 00 00 00 E0 91 07 00

The math:

start LBA 32      -> CHS 0/0/33 -> bytes 00 21 00
end LBA 496127    -> CHS 492/3/3 -> bytes 03 43 EC

That got the CF past the PC BIOS handoff and into preboot-300. For the first time, the new card was acting like a boot disk.

Then preboot-300 said:

No filesystem found on device
can't boot, unknown file system

Progress, but not enough.

The misleading gzip test

The image had two gzip magic offsets:

FSYS.gz   at byte 5000704
FSYS1.gz  at byte 6009856

At first I extracted bytes linearly from those offsets and ran gunzip -t. Both failed with CRC errors. That looked terrible.

It was also wrong.

The files are not stored contiguously. Raw dd from the first gzip byte reads the first extent, then keeps going into unrelated filesystem blocks. The right way is to walk the CNi inode/block map.

Once I wrote a small extractor for the CNi filesystem, both v3 root images validated:

FSYS.gz   compressed 1000390 bytes  gunzip OK
FSYS1.gz  compressed  676628 bytes  gunzip OK

That was a good reminder: with old filesystems, a familiar magic number is not the same thing as a file boundary.

The second patch: repairing the CNi superblock

The real filesystem failure was in the CNi superblock.

The superblock lives at partition LBA + 1. For the v3 image, that is absolute LBA 33, byte offset 0x4200.

The first part of the sector still had sane accounting fields:

nin:               59
total inode slots: 31004
total blocks:      496096
free inodes:       30946

But the rest of the sector was obviously damaged. Where the older working v2 DOM had signatures and zero-filled fields, the v3 DOM had repeating 0x80 bytes.

The working v2 superblock contained these magic values:

11112222
34aae5fe
cafefeca
1fedface

Those values were missing from the v3 clone.

The repaired v3 superblock restored the known-good structure while keeping the v3 size fields:

offset 0x24: 00000008
offset 0x28: 11112222
offset 0x2c: 34aae5fe
offset 0x30: cafefeca
offset 0x34: 00000200
offset 0x38: 1fedface
offset 0x3c: 00001e4a
offset 0x40: 00000020
offset 0x44: e5 repeated for 20 bytes
offset 0x58: 003f0000
rest:        zeroes

One field still looked suspicious: free_blocks.

The damaged v3 superblock said:

total_blocks = 496096
free_blocks  = 491648
used_blocks  = 4448

But walking the inode/block maps showed more than 5,000 allocated file blocks before counting reserved metadata. So free_blocks was recomputed to match the actual structure:

first_data_block      = 0x1e4a = 7754
allocated file blocks = 5191
used blocks           = 12945
free_blocks           = 496096 - 12945 = 483151

That final repaired image became:

nuova-CF-ready-v3-superfix4.img

It had:

  • the CF 16/63 CHS MBR patch
  • the repaired CNi superblock
  • the original v3 kernel
  • the original v3 FSYS.gz and FSYS1.gz

On the Athlon test PC it got to:

Loading... loaded

and then stopped at a blinking cursor. That led to another detour.

The hybrid image

There was an older 4 MB DOM image from the same machine, from a previous software version. It booted farther on the Athlon, all the way to the NFS retry loop:

.vdcnc:/c/CN on /server rw

So I built a diagnostic hybrid image:

  • v3 filesystem
  • v3 FSYS.gz
  • v3 FSYS1.gz
  • old v2 lynx.os-300 kernel copied into the v3 kernel inode

This proved something important: the v3 filesystem and root payload were good. The full v3 kernel simply did not like the Athlon test PC.

At this point I was leaning toward “try pure v3 on the real NC1000, keep the hybrid as fallback.”

Then the real machine changed the story again.

The false villain: the CF card

On the NC1000, the CF kept failing with:

Cannot open device h0a

At first that looked like a CF compatibility problem. Maybe the Verbatim reported as removable media. Maybe CNi preboot-300 used its own IDE driver and rejected it. Maybe the CF could be read by BIOS enough to load preboot, but not opened later as h0a.

That theory was plausible. It was also wrong.

We tried:

  • the repaired v3 image
  • the hybrid image
  • the old v2 image
  • original CHS
  • CF CHS
  • relocating the partition to LBA 63
  • writing to a real Samsung PATA hard disk
  • rewriting the original 256 MB DOM

Everything failed the same way on the NC1000:

Cannot open device h0a

The breakthrough came from the simplest possible hardware test: move the storage to the other IDE slot/header on the NC1000 motherboard.

It loaded immediately.

The original IDE slot was bad.

The fix

The final working setup was:

media:     Verbatim 4 GB CF in CF-to-IDE adapter
slot:      the second/good IDE slot on the NC1000 motherboard
image:     nuova-CF-ready-v3-superfix4.img
jumper:    Master

Once it was in the good slot, the same CF that had looked “incompatible” booted the repaired v3 image all the way through. The machine reached LynxOS, mounted:

vdcnc:/c/CN on /server rw

and started the XNC environment.

The old 256 MB DOM was still not trustworthy. Even after rewriting it, it continued to produce filesystem errors. The CF became the practical replacement, and the next step was to snapshot the known-good bootable CF as the new golden image.

The useful lessons

The main lesson is not “AI fixed a CNC.” The useful part was the style of debugging: slow, layered, and willing to discard yesterday’s theory.

The low-level patches mattered. Without the CHS patch, the CF would not load preboot. Without the superblock patch, preboot rejected the v3 filesystem. Without the inode extractor, FSYS.gz looked corrupted when it was actually fine.

But the final fault was hardware: a bad IDE slot. No amount of beautiful image patching can fix a failing connector.

The second lesson is that old industrial boot paths have layers:

BIOS can read enough sectors to boot
does not imply
CNi preboot can open h0a
does not imply
LynxOS can mount the root payload
does not imply
the application can reach the Windows NFS share

Each layer needs its own evidence.

The third lesson is that AI is genuinely useful in this kind of work when it is treated like a tireless second engineer, not an oracle. Opus 4.7 and GPT-5.5 helped map strings to boot architecture, decode partition entries, derive CHS values, compare binary structures, and keep the investigation moving. They also made wrong calls along the way. The important part was having enough concrete evidence - sector dumps, boot messages, checksums, and live tests - to correct those calls quickly.

In the end, the CNC came back because old-school repair and modern tooling met in the middle: a hex editor mindset, a pile of boot logs, a CompactFlash card, and a patient loop of “patch, flash, boot, observe.”

That is exactly the kind of debugging I like.