Personal tools

O.S. update service

From Variscite Wiki

Jump to: navigation, search

WindowsCE O.S. update service


1 Overview

Variscite's Windows CE BSP includes a proprietary OS update service.

The service provides the ability to remotely update the OS run-time-image which resides on the on-board NAND-flash.

Windows embedded compact 7 releases 1.25 and forth, support EBOOT, boot configuration and screen logo update as well.

O.S. update procedure is power-fail proof.  OS image will not replace current one, until the flashing process is successfully completed and verified.

All other updates are not power fail proof, user must ensure proper power stability before procedure start.


2 Boot Configuration API

Boot configuration structure (BOOT_CFG) declared in file boot_args.h Two IOCTLs provided: OSU_IOCTL_READ_BOOTARGS - Reads boot configuration from flash memory into user buffer OSU_IOCTL_WRITE_BOOTARGS - Saves boot configuration from user buffer into flash memory Note that OSU_IOCTL_WRITE_BOOTARGS is not fail-safe: if for some reason (like power removal) if will fail, it may leave boot configuration in undefined state.

3 OS image, EBOOT and Logo update API

OS image update (like EBOOT and Logo update) uses two IOCTLs:
OSU_IOCTL_SET_FILE - Sets the file-name for consequent update operation. For OS image update file shall be of "nb0" (raw binary) type.
OSU_IOCTL_UPDATE - Initiates the OS image update procedure

Updating EBOOT also uses two IOCTLs: same OSU_IOCTL_SET_FILE followed by OSU_IOCTL_UPDATE_EBOOT. EBOOT file shall be in "nb0" (raw binary) format. Please ensure that correct file is specified, because there is no way for the driver to determine that raw binary contains EBOOT.

Updating EBOOT also uses two IOCTLs: same OSU_IOCTL_SET_FILE followed by OSU_IOCTL_UPDATE_LOGO. Logo file shall be in "bmp" (24-bit RGB) format. Make sure that supplied bitmap has exactly the size of your screen, otherwise it will not be displayed correctly by EBOOT.


Note:
The NK.nb0 and EBOOTND.nb0 files are generated as part of OS build. The files may be found in the Release directory under the corresponding project. For example, if the user builds the VAR_SOM-OM37_P BSP with VAR-SOM-OM3X_REL project, then the file will reside in the \WINCE600\Osdesign\VAR-SOM-OM3X_REL\VAR-SOM-OM3X_REL\RelDir\VAR_SOM_OM37_P_ARMV4I_Release folder.


Note:
The OS update procedure requires reboot for updated OS image activation. User should reset the system when ready.

Application may use the following command to reset the system:

SetSystemPowerState(NULL, POWER_STATE_RESET, 0);
Note:
The driver uploads full OS image file to the RAM. Therefore, for successful update operation, driver requests 32M of free RAM.

Service limitation: OS update service nk0 size limit:

Windows CE6: 40MB

Windows embedded compact 7:  VAR-SOM-AM35   -  80MB, VAR-SOM-OM37 - 62MB

4 Sample application - all O.S. update features

Note that preprocessor variable DYNAMIC_OS_BOOT must be defined (in project properties)
// OSUpdate.cpp : Defines the entry point for the console application.
//
#pragma warning(push)
#pragma warning(disable : 4115 6067)
#include <windows.h>
#include "oalex.h"
#include "boot_args.h"

void RetailPrint(wchar_t *pszFormat, ...);
//extern int	CreateArgvArgc(TCHAR *pProgName, TCHAR *argv[20], TCHAR *pCmdLine);

#define OSU_IOCTL_BASE				0x35300000
#define OSU_IOCTL_SET_FILE			((OSU_IOCTL_BASE)+0)
#define OSU_IOCTL_UPDATE			((OSU_IOCTL_BASE)+1)
#define OSU_IOCTL_UPDATE_EBOOT		((OSU_IOCTL_BASE)+2)
#define OSU_IOCTL_UPDATE_LOGO		((OSU_IOCTL_BASE)+3)
#define OSU_IOCTL_READ_BOOTARGS		((OSU_IOCTL_BASE)+4)
#define OSU_IOCTL_WRITE_BOOTARGS	((OSU_IOCTL_BASE)+5)

TCHAR	strOsImage[MAX_PATH] = L"\\Hard Disk\\NK.nb0";
TCHAR	strOsEboot[MAX_PATH] = L"\\Hard Disk\\Eboot.nb0";
TCHAR	strOsLogo[MAX_PATH] = L"\\Hard Disk\\logo.bmp";
BOOT_CFG BootArgs;

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR lpCmdLine, int nCmShow)
{
	HANDLE		hDrvContext;
	DWORD		dwErr=1;
	DWORD		dwRet;
    
    UNREFERENCED_PARAMETER(hInst);
    UNREFERENCED_PARAMETER(hPrevInst);
    UNREFERENCED_PARAMETER(nCmShow);

	// Open OSU driver
	hDrvContext = 
        CreateFile(L"OSU0:", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);

	if (hDrvContext == INVALID_HANDLE_VALUE) {
		RETAILMSG(1, (TEXT("ERROR: Can't open OSU driver\r\n")));
		return -1;
	}	

	RETAILMSG(1, (TEXT("Reading boot config\r\n")));
	if (!DeviceIoControl(hDrvContext, OSU_IOCTL_READ_BOOTARGS, NULL, 0, &BootArgs, sizeof(BootArgs), &dwRet, NULL))
	{
		RETAILMSG(1, (L"ERROR: can't read Boot_CFG, err = %d\r\n", GetLastError()));
	}
	RETAILMSG(1, (L"Boot Args ver %d signature %x\r\n", BootArgs.version, BootArgs.signature));

	if (!DeviceIoControl(hDrvContext, OSU_IOCTL_WRITE_BOOTARGS, &BootArgs, sizeof(BootArgs), NULL, 0, &dwRet, NULL))
	{
		RETAILMSG(1, (L"ERROR: can't write Boot_CFG, err = %d\r\n", GetLastError()));
	}
	
        RetailPrint(TEXT("Updating Eboot from %s\n"), strOsEboot);
	DeviceIoControl(hDrvContext, OSU_IOCTL_SET_FILE, strOsEboot, _tcslen(strOsEboot)*sizeof(TCHAR), NULL, 0, NULL, NULL);	

	// start update process
	if (!DeviceIoControl(hDrvContext, OSU_IOCTL_UPDATE_EBOOT, NULL, 0, NULL, 0, NULL, NULL))
	{		
		LPVOID lpMsgBuf = NULL;
		DWORD dw = GetLastError(); 

		// REQUIRES SYSGEN_FMTMSG AND SYSGEN_FMTRES
		dwErr = FormatMessage(
			FORMAT_MESSAGE_ALLOCATE_BUFFER | 
			FORMAT_MESSAGE_FROM_SYSTEM |
			FORMAT_MESSAGE_IGNORE_INSERTS,
			NULL,
			dw,
			0,
			(LPTSTR) &lpMsgBuf,
			512, NULL );

		// Display the error message		
		RETAILMSG(1, (L"ERROR: can't update Logo, err = %d/%d, %s\r\n", dw, dwErr, lpMsgBuf));		
	}

	RetailPrint(TEXT("Updating Logo from %s\n"), strOsLogo);

	DeviceIoControl(hDrvContext, OSU_IOCTL_SET_FILE, strOsLogo, _tcslen(strOsLogo)*sizeof(TCHAR), NULL, 0, NULL, NULL);	

	// start update process
	if (!DeviceIoControl(hDrvContext, OSU_IOCTL_UPDATE_LOGO, NULL, 0, NULL, 0, NULL, NULL))
	{		
		LPVOID lpMsgBuf = NULL;
		DWORD dw = GetLastError(); 

		// REQUIRES SYSGEN_FMTMSG AND SYSGEN_FMTRES
		dwErr = FormatMessage(
			FORMAT_MESSAGE_ALLOCATE_BUFFER | 
			FORMAT_MESSAGE_FROM_SYSTEM |
			FORMAT_MESSAGE_IGNORE_INSERTS,
			NULL,
			dw,
			0,
			(LPTSTR) &lpMsgBuf,
			512, NULL );

		// Display the error message		
		RETAILMSG(1, (L"ERROR: can't update Logo, err = %d/%d, %s\r\n", dw, dwErr, lpMsgBuf));		
	}

	RetailPrint(TEXT("Updating NK image from %s\n"), strOsImage);
	// set file name holding new OS image
	DeviceIoControl(hDrvContext, OSU_IOCTL_SET_FILE, strOsImage, _tcslen(strOsImage)*sizeof(TCHAR), NULL, 0, NULL, NULL);
	// start update process
	if (!DeviceIoControl(hDrvContext, OSU_IOCTL_UPDATE, NULL, 0, NULL, 0, NULL, NULL))
	{		
		LPVOID lpMsgBuf = NULL;
		DWORD dw = GetLastError(); 

		// REQUIRES SYSGEN_FMTMSG AND SYSGEN_FMTRES
		dwErr = FormatMessage(
			FORMAT_MESSAGE_ALLOCATE_BUFFER | 
			FORMAT_MESSAGE_FROM_SYSTEM |
			FORMAT_MESSAGE_IGNORE_INSERTS,
			NULL,
			dw,
			0,
			(LPTSTR) &lpMsgBuf,
			512, NULL );

		// Display the error message		
		RETAILMSG(1, (L"ERROR: can't update OS, err = %d/%d, %s\r\n", dw, dwErr, lpMsgBuf));		
	}

    return 0;
}

///////////////////////////////////////////////////////////////////////////////
// Used to show message serial terminal AND console window
void RetailPrint(wchar_t *pszFormat, ...)
{
    va_list al;
    wchar_t szTemp[2048];
    wchar_t szTempFormat[2048];

    va_start(al, pszFormat);
    vwprintf(pszFormat, al);
    // Show message on RETAILMSG
    swprintf(szTempFormat, L"OSUPDATE: %s\r", pszFormat);
    pszFormat = szTempFormat;
    vswprintf(szTemp, pszFormat, al);
    RETAILMSG(1, (szTemp));

    va_end(al);
}
#pragma warning(pop)