Booting VxWorks from NAND Flash on S3C2440 ARM9
Booting an embedded real-time operating system directly from NAND Flash can reduce hardware cost, increase storage capacity, and simplify board design. However, NAND Flash does not support conventional execute-in-place (XIP) operation, so a processor must first execute a small amount of code from another memory region before loading the operating system into RAM.
The Samsung S3C2440 ARM9 processor provides a practical solution to this challenge through its built-in 4KB stepping-stone SRAM. During NAND boot, the processor copies the initial boot code from NAND Flash into this internal SRAM and begins execution there. That code can then initialize external memory, access NAND Flash, and load a larger bootloader into SDRAM.
This article explains how to adapt the VxWorks boot process to this architecture, covering the hardware platform, multi-stage boot sequence, BSP modifications, NAND-specific reliability requirements, and system validation.
For related implementation details, see the VxWorks NAND Flash boot design for S3C2440 and the broader VxWorks BSP development guide.
🚀 Why Boot VxWorks from NAND Flash? #
NOR and NAND Flash serve different purposes in embedded systems.
NOR Flash supports random access and execute-in-place operation, making it suitable for storing small bootloaders and firmware that must execute directly from nonvolatile memory. NAND Flash offers higher storage density and generally lower cost per bit, making it attractive for larger firmware images and data storage.
Traditional embedded designs sometimes combine the two:
- NOR Flash stores the initial bootloader.
- NAND Flash stores the operating-system image and other data.
- SDRAM provides working memory for the running system.
Although effective, this approach requires multiple storage devices and additional board resources.
A NAND-only boot architecture can eliminate the external NOR device, reducing the bill of materials and potentially simplifying PCB layout.
The challenge is that the processor cannot simply execute instructions directly from NAND Flash. The boot design must establish a small initial execution environment and then transfer the remaining code into executable memory.
On the S3C2440, the built-in stepping-stone SRAM makes this possible.
The S3C2440 Stepping-Stone Advantage #
The S3C2440 is based on the ARM920T core and includes a small internal SRAM region used during early NAND boot.
When the processor starts in the appropriate NAND boot mode, hardware transfers the first 4KB of NAND Flash into this SRAM region. The processor can then execute the initial boot code without requiring external NOR Flash.
This creates the foundation for a multi-stage boot process:
- Execute a compact first-stage loader from internal SRAM.
- Initialize external SDRAM and NAND access.
- Load a larger bootloader from NAND into SDRAM.
- Load the VxWorks image into memory.
- Transfer control to the operating system.
The major constraint is the limited space available to the first stage. The initial code must remain small enough to fit within the 4KB stepping-stone region, so extensive initialization and image-loading functions belong in a later stage.
🧩 Hardware Platform Overview #
The prototype configuration described in the original implementation used the following hardware:
| Component | Configuration |
|---|---|
| Processor | Samsung S3C2440, ARM920T |
| Internal SRAM | 4KB stepping-stone region |
| NAND Flash | Samsung K9F2G08U0B, 256MB |
| External memory | 64MB SDRAM |
| Ethernet | DM9000 controller |
| Operating system | VxWorks |
The hardware provides three distinct memory roles.
Stepping-stone SRAM holds the initial boot code.
NAND Flash stores the bootloader and VxWorks image in nonvolatile form.
SDRAM provides the larger execution environment required for the bootloader, operating-system image, kernel data, and applications.
The Ethernet controller supplies network connectivity for functions such as remote debugging and application communication once the relevant drivers and software services are initialized.
The exact memory addresses, initialization values, and NAND geometry must be taken from the target board’s hardware documentation.
⚙️ Understanding the VxWorks Boot Process #
A conventional VxWorks boot sequence on legacy platforms commonly involves low-level startup routines such as romInit and romStart, followed by system initialization.
The precise sequence depends on the VxWorks release, BSP, image format, and bootloader architecture.
For a NAND-based S3C2440 implementation, the standard startup flow must be adapted to account for the stepping-stone SRAM and NAND’s page-oriented storage model.
Stage 1: Execute from Stepping-Stone SRAM #
The processor begins execution from the initial code copied from NAND Flash into its internal SRAM.
This first stage performs only essential work:
- Establish the minimal processor execution environment.
- Configure the NAND controller sufficiently for reading the remaining boot code.
- Initialize the SDRAM controller using the required timing parameters.
- Read the larger bootloader from NAND.
- Transfer execution to the bootloader in SDRAM.
The 4KB limit makes code-size control critical. Large lookup tables, unnecessary diagnostics, and general-purpose library functions can quickly consume the available space.
The first stage should therefore be kept small and deterministic, with most boot logic deferred to the larger second stage.
Stage 2: Execute the Full Bootloader from SDRAM #
Once SDRAM is operational, the bootloader has substantially more room for initialization and storage operations.
Its responsibilities can include:
- Completing memory configuration.
- Reading the VxWorks image from NAND Flash.
- Handling the NAND layout and image offsets.
- Validating the loaded image where supported.
- Copying or decompressing the image into its designated RAM location.
- Preparing boot parameters.
- Transferring control to the VxWorks entry point.
A simplified flow is:
S3C2440 Reset
|
v
Hardware Loads Initial 4KB
|
v
Stepping-Stone SRAM
|
v
Initialize NAND and SDRAM
|
v
Load Full Bootloader into SDRAM
|
v
Read VxWorks Image from NAND
|
v
Prepare Image and Boot Parameters
|
v
VxWorks StartupThis approach separates the minimal hardware initialization required immediately after reset from the larger tasks necessary to launch the operating system.
Stage 3: Initialize VxWorks #
After the bootloader prepares the operating-system image and transfers control, the VxWorks startup routines continue initialization.
In a typical legacy BSP, this involves the low-level assembly entry point, C startup routines, hardware initialization, kernel initialization, and application startup.
Depending on the image configuration, routines such as romInit, romStart, sysInit, and usrInit may participate in different parts of this process.
The NAND loader must integrate with the startup mechanism expected by the particular BSP. It should not assume that every VxWorks version uses an identical entry sequence or image layout.
Once startup completes, the kernel and applications execute from SDRAM, while NAND Flash can remain available for persistent image storage and other data.
🔧 Implementing the NAND Bootloader #
The core implementation challenge is moving from the 4KB stepping-stone environment to the full SDRAM-based bootloader.
The design needs to account for the NAND device’s physical organization, the board’s memory controller configuration, and the image format expected by VxWorks.
NAND Page Reads #
Unlike NOR Flash, NAND devices organize storage into pages and erase blocks.
Bootloader code must issue the correct control sequences to select the device, specify the page address, trigger a read operation, and transfer data into memory.
The implementation must follow the commands, addressing scheme, and timing requirements of the particular NAND device.
It should also distinguish between the physical NAND layout and the logical image layout used by the boot process.
Bad-Block Management #
NAND Flash may contain factory-marked bad blocks, and additional blocks can become unreliable during the device’s lifetime.
A bootloader that assumes every physical block is usable can fail when an image crosses a bad block.
A reliable design needs an explicit policy for bad-block handling and image placement. Depending on the storage layout, this may involve skipping marked blocks, using a defined image region, or relying on a validated higher-level storage format.
The first-stage code must remain small, so the NAND layout and recovery policy should be designed with the 4KB constraint in mind.
Error-Correction Code #
NAND data may contain bit errors, making error-correction support another important part of the implementation.
The required ECC strength depends on the NAND device’s specifications and the reliability requirements of the stored boot image.
The bootloader’s read implementation must use an ECC scheme compatible with the way the image was programmed. A mismatch between programming and reading can make an apparently valid image unusable.
Image Placement and Validation #
The bootloader must know where the bootloader image and VxWorks image reside in NAND, where they should be loaded in SDRAM, and how control should pass between stages.
The memory map must avoid overlap among:
- Initial boot data
- Full bootloader
- VxWorks image
- Decompression workspace
- Kernel data
- Stack and heap regions
- Other reserved memory
Where the platform supports image integrity checks, validation should occur before transferring execution to the loaded image.
🛠️ Modifying the VxWorks BSP #
The Board Support Package connects VxWorks to the processor and board hardware. For NAND boot, its startup code and memory configuration must work with the new loading sequence.
The original implementation required changes to the BSP, including low-level startup code in romInit.s and adjustments to memory-layout assumptions.
Startup-Code Changes #
The initial startup routine must be adapted so that the processor can move from stepping-stone SRAM into the SDRAM-based boot environment.
This requires careful handling of the processor’s execution state, stack, register configuration, and transition to the larger loader.
The startup code should also avoid depending on initialized memory or services that are not yet available.
Memory Configuration #
The memory map must reflect the actual board configuration and distinguish between the initial SRAM region, SDRAM execution regions, and NAND storage addresses.
Memory configuration mistakes can cause subtle failures, including corrupted images, overwritten stack data, or jumps to invalid addresses.
For reliable startup, verify the address ranges and image sizes against the actual linker and BSP configuration rather than relying on assumptions from another board.
Boot Image Generation #
The final image must be compatible with the bootloader’s expected format and loading behavior.
A typical development workflow is:
- Modify the BSP startup code and memory configuration.
- Build the appropriate VxWorks image using the target toolchain.
- Build the first-stage loader and full bootloader.
- Prepare the NAND image layout.
- Program the boot components and operating-system image.
- Verify the contents and offsets of the programmed image.
- Test a complete power-on boot.
The original implementation used JTAG-assisted programming during development. The programming procedure and image layout should be adapted to the available hardware tools and target NAND device.
For related low-level startup, driver, and board-initialization work, see the VxWorks BSP development guide and the VxWorks BSP development handbook.
🧪 Testing and Validating NAND Boot #
A bootloader that succeeds once is not necessarily reliable enough for production.
Validation should cover the entire path from reset through operating-system initialization, including NAND access, SDRAM setup, image loading, and recovery from invalid data.
Boot-Sequence Validation #
First, verify each stage independently.
| Test stage | What to verify |
|---|---|
| Initial boot | CPU executes the first-stage code from SRAM |
| SDRAM setup | Memory initialization completes and addresses are usable |
| NAND access | Page reads return the expected data |
| Bootloader loading | The full loader is placed correctly in SDRAM |
| Image loading | The correct VxWorks image reaches its destination |
| Kernel startup | VxWorks completes system initialization |
| Device startup | Required drivers and interfaces initialize |
| Application operation | The application runs under the expected workload |
Serial diagnostic output or JTAG inspection can help identify the stage where startup fails.
NAND Reliability Tests #
Additional tests should exercise NAND-specific failure conditions:
- Bad-block handling
- ECC detection and correction
- Invalid or corrupted images
- Unexpected power interruption during image updates
- Incorrect image offsets
- Repeated cold starts
- Recovery when a stored image cannot be loaded
If the design supports firmware updates, the update procedure should also protect against interruptions that could leave the board unable to boot.
Runtime Validation #
After VxWorks starts, verify that the expected system services operate correctly.
For the example platform, this includes confirming that the kernel shell is available and that the required networking, task scheduling, and peripheral functions initialize normally.
The reported prototype results included a shell becoming available within a few seconds, operational networking and task scheduling, and an estimated hardware cost reduction of approximately 20% compared with a design using both NOR and NAND Flash.
These figures describe the reported prototype and should not be treated as universal results. Actual savings and boot time depend on component prices, image size, initialization complexity, NAND characteristics, and the reliability requirements of the final product.
📉 Benefits and Engineering Trade-Offs #
NAND-only boot offers several practical advantages.
Lower hardware cost: Removing an external NOR Flash device can reduce component count and storage-related costs.
Simpler PCB design: Fewer storage components may reduce board area and routing requirements.
Greater storage capacity: NAND provides room for operating-system images, application software, and other persistent data.
Reusable boot architecture: The separation between a small first-stage loader and a larger RAM-based bootloader is a useful pattern for other embedded platforms.
However, NAND-only boot also increases bootloader complexity.
The design must handle NAND addressing, bad blocks, ECC, SDRAM initialization, image placement, and failure recovery. The small stepping-stone region adds another constraint because the initial code has very little space available.
The right choice therefore depends on the complete product design. NAND-only boot is attractive when cost and storage capacity matter and the engineering effort required for reliable boot handling is justified.
🔮 Lessons for Modern Embedded Systems #
The S3C2440 is a legacy ARM9 processor, but the fundamental boot-design principles remain relevant to embedded systems.
Modern platforms also commonly separate early initialization from the larger bootloader and operating-system stages. Storage technologies and processor boot mechanisms differ, but the same engineering problems continue to appear: establishing working memory, loading images safely, validating boot data, and handling failure conditions.
For engineers maintaining legacy ARM9 products, the S3C2440’s stepping-stone mechanism provides a useful example of how hardware boot features can reduce external component requirements.
For new embedded products, the broader lesson is that boot architecture should be designed together with the BSP, memory map, storage format, update mechanism, and recovery strategy.
✅ Conclusion #
Booting VxWorks from NAND Flash on the S3C2440 ARM9 demonstrates how a small hardware-assisted startup mechanism can eliminate the need for external NOR Flash.
The essential design is a multi-stage boot process:
- Use the processor’s 4KB stepping-stone SRAM for initial execution.
- Initialize NAND access and external SDRAM.
- Load the full bootloader into SDRAM.
- Read and prepare the VxWorks image.
- Transfer control to the operating-system startup code.
- Validate the complete boot and runtime environment.
The most difficult work lies in the details: fitting the first-stage loader into a very small memory region, correctly handling NAND pages and bad blocks, maintaining ECC compatibility, and ensuring that the BSP’s startup logic matches the actual memory layout.
When these components are engineered and tested together, NAND-only boot can provide a cost-effective solution for legacy ARM9 platforms and other embedded systems with strict hardware constraints.
For further implementation guidance, explore the S3C2440 VxWorks NAND boot guide and the broader VxWorks BSP resources.