OAL IOCTLs are callable from OAL code to perform specific functions within the OS Kernel. The OS requires the OEM to specifically implement certain IOTLCs that it calls, and some other standard IOTCLs if implemented are automatically called by the OS. One such optional IOCTL, IOCTL_HAL_GET_HIVE_CLEAN_FLAG, will cause the OS to clear the hive registry if it passes back a TRUE value when called at OS startup. These IOCTLs are normally called in kernel mode as they are called directly by the the kernel. Some IOCTLs can be called by a user mode thread as well. In our book, Professional Windows Embedded Compact 7, I covered implementing a custom OAL IOCTL for the Virtual CEPC BSP. This blog looks at adding an OAL IOCTL with the ARM TI AM335X BSP
In this blog, we will look at adding the IOCTL_HAL_GET_HIVE_CLEAN_FLAG OAL IOCTL to enable the cleaning of the System and User registry hives at boot time. If a hive registry is used then the registry persists between boot in external storage such as a disk drive or in flash. With external storage such as with x86 systems, such as VECPC (x86) WE Compact systems, it is a simple matter of deleting system.hv and user.hv from the disk drive and doing an immediate reboot to clear the hive. With systems that use flash for persistent hive storage, such as the AM335X, attempts to manually delete the hive files fail and so the IOCTL needs to be used. This will be a fixed (will always clear the hive) implementation. Subsequent blogs in this series will embellish this functionality with more complex capabilities such as eboot menu options and runtime flagging of the need to clear it upon reboot. This functionality is discussed at the following links:
IOCTL_HAL_GET_HIVE_CLEAN_FLAG is called by FileSys once the File System is loaded, as that is needed to read the registry form Flash or storage into RAM. The Registry is actually used in RAM by the OS. Registry flushing involves writing registry entries in RAM back to flash or storage. This may occur manually (programmatically), periodically, whenever a registry value changes or at shutdown.
Context: This discussion is with respect to the Texas Instruments AM335X MPU as used with BeagleBone Black (BBB) and the Variscite VAR-SOM-AM33. This material was developed mainly with the latter but the BBB was also used in parts.
I couldn't find a complete implementation of this so here goes:
1. In ioctl_tabh.h insert the following as highlighted in yellow (curly braces not brackets!). This adds it to the list OAL IOCTLs available to the OS and links it to the function that implements it.
// Required Termination { 0, 0, NULL }
2. Insert the foillowing fucntion to ioctl.c. I added it after the OALIoCtlHalGetPowerDisposition() fucntion.
BOOL OALIoctlHalGetHivewCleanFlag(UINT32 code, VOID *pInBuffer, UINT32 inSize, VOID *pOutBuffer, UINT32 outSize, UINT32 *pOutSize) {
DWORD *pdwFlags = (DWORD*)pInBuffer; DWORD mode = *pdwFlags ; return TRUE;
}
3. Set the OS to Debug (with KITL and VMINI enabled) and build the OS. Resolve any coding issues.
Hint: You can right click on the OALtree and build just that whilst just getting the syntax etc of the that complete but you will need to build the whole OS once the local build options have been resolved.
4. Set a breakpoint on the return line True and run the OS. Observe that it hits the breakpoint three times.Twice for the System hive (not sure why its twice) and once for the User hive. Observe the mode in each case.
5.Implement the "static" version of the the IOCTL using the code as per the MSDN as above (slightly modified):
BOOL OALIoctlHalGetHivewCleanFlag(UINT32 code, VOID *pInBuffer, UINT32 inSize, VOID *pOutBuffer, UINT32 outSize, UINT32 *pOutSize) { //case IOCTL_HAL_GET_HIVE_CLEAN_FLAG: BOOL fRet= TRUE; FILE * pFile= NULL; if ( (!pInBuffer) || ( inSize != sizeof(DWORD)) || (!pOutBuffer) || (outSize != sizeof(DWORD))) { //SetLastError(ERROR_INVALID_PARAMETER); //No linkage for SetLstError(): ToDo RETAILMSG(1, (L"OEM: Not cleaning system/user regsitry hive\r\n")); fRet = FALSE; } else { DWORD *pdwFlags = (DWORD*)pInBuffer; BOOL *pfClean = (BOOL*) pOutBuffer; if (*pdwFlags == HIVECLEANFLAG_SYSTEM) { *pfClean = TRUE; RETAILMSG(1, (L"OEM: Clearing system registry hive\r\n"));
} else if (*pdwFlags == HIVECLEANFLAG_USERS) { *pfClean = FALSE; RETAILMSG(1, (L"OEM: NOT Clearing user registry hive\r\n")); } } return fRet; }
6. Rebuild the OS and test as in 4.
Typical output::
As coded above the OS will always clear the System hive and leave the User hive intact when it boots. What is needed is a mechanism to make this user selectable. One method would be for this be selected as part of the eBoot menu. An alternative would be the user to set a flag whilst the OS is running that would survive a reboot. These will be discussed in subsequent blogs. These approaches will be developed in subsequent blogs.
What about just reflashing the the OS with the same nk.bin/nb0 file? .. NO! Sue Loh discusses what happens when an OS image is booted. If the reginit.ini hash value is different then the hives are cleared. If not then this doesn't happen. So if you flash and boot the same image (or one with no registry changes) then the hive won't be cleared. Make any trivial change and it will be cleared. though.
In <WECROOT>\Platform\<BSP>\SRC\OAL\oalioctl\oalioctl.cpp are the IOCTL implementations that user mode threads can call into the kernel via KernelIoControl. (I haven't tried this).