Copyright 2017,2018 IBM
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
This document describes the reference mailbox daemon contained in this repository.
The main mailbox daemon is implemented in mboxd.c. This file uses helper functions from the various mboxd_*.c files.
dbus.c - Contains the handlers for the D-Bus commands which the daemon can receive. flash.c - Contains the functions for performing flash access including read, write and erase. lpc.c - Contains the functions for controlling the LPC bus mapping including pointing the bus so it maps flash and memory. mboxd_msg.c - Contains the handlers for the mbox commands which the daemon can receive. windows.c - Contains the functions for managing the window cache.
The daemon is a state machine with 5 valid states:
UNINITIALISED - The daemon is still in the initialisation phase and will not respond ACTIVE_MAPS_FLASH - The daemon is polling for incoming commands, is not currently suspended and the LPC bus maps the flash device. SUSPEND_MAPS_FLASH - The daemon is polling for incoming commands, is currently suspended and the LPC bus maps the flash device. ACTIVE_MAPS_MEM - The daemon is polling for incoming commands, is not currently suspended and the LPC bus maps the reserved memory region. SUSPEND_MAPS_MEM - The daemon is polling for incoming commands, is currently suspended and the LPC bus maps the reserved memory region.
As described in the protocol, the daemon can be suspended to allow the BMC to access flash without the daemon interfering. The daemon will still respond to commands while suspended but won't allow the host to, or itself, access the flash.
UNINITIALISED -> ACTIVE_MAPS_FLASH - Uninitiated: Occurs when the daemon is finished initialising. ACTIVE_MAPS_FLASH -> SUSPEND_MAPS_FLASH - Suspend command received over D-Bus SUSPEND_MAPS_FLASH -> ACTIVE_MAPS_FLASH - Resume command received over D-Bus ACTIVE_MAPS_MEM -> SUSPEND_MAPS_MEM - Suspend command received over D-Bus SUSPEND_MAPS_MEM -> ACTIVE_MAPS_MEM - Resume command received over D-Bus ACTIVE_MAPS_FLASH -> ACTIVE_MAPS_MEM - GET_MBOX_INFO command received SUSPEND_MAPS_FLASH -> SUSPEND_MAPS_MEM - GET_MBOX_INFO command received ACTIVE_MAPS_MEM -> ACTIVE_MAPS_FLASH - Reset D-Bus or mbox command received SUSPEND_MAPS_MEM -> SUSPEND_MAPS_FLASH - Transition not allowed, we don't let the host modify flash while the daemon is suspended.
While the protocol describes that there is only one active window at a time, the daemon keeps a cache of previously accessed windows to avoid the need to reload them from flash should the host access them again in the future.
The reserved memory region is divided among a number of windows which make up the window cache. When the host requests a flash offset the cache is searched for one which contains that offset. If one is found we simply point the host to it at the correct LPC offset for that windows location and the requested flash offset.
If there is no window in the cache which contains the requested flash offset then we have to find one to load with the requested flash contents. If there are any windows which are empty then we choose those, otherwise, we choose one to evict using a least recently used (LRU) scheme. The flash is then copied into this window and the host pointed at its location on the LPC bus.
When ever the flash is changed we have to invalidate all windows in the window cache as their contents may no longer accurately reflect those of the flash.
The daemon is invoked on the command line with a few parameters:
(*) - required (#) - optional but recommended (~) - optional --flash * - The size of the PNOR image on the flash device --window-size # - The size to make each window in the cache --window-num # - The number of windows to have in the cache --verbose ~ - Increase the verbosity with which the daemon runs --sys-log ~ - Use the system log rather than outputting to the console
If any of the required parameters are missing or invalid an error will be printed and the daemon will terminate. If window-size and window-num aren't specified then the default is to have a single window which spans the entire reserved memory region.
After the command line has been parsed the daemon will initalise its various interfaces. If any of these initialisations fail it will print an error and the daemon will terminate.
After initilisation, the daemon points the LPC mapping to the actual flash device, sets the BMC_READY BMC event and starts polling.
The daemon sits in a poll loop waiting for an event to happen on one or more of the mbox, D-Bus or signal file descriptors.
When an event occurs on the mbox file descriptor the mbox request is read from the mbox registers and processed.
The command is validated and then the appropriate handler called. The response is then written back to the mbox registers to indicate the outcome of the command and an interrupt is sent to the host.
When an event occurs on the D-Bus file descriptor the D-Bus request is read from the D-Bus interface and processed.
The command is validated and then the appropriate handler called. The response is then written back to the D-Bus interface to indicate the outcome of the command.
The daemon blocks SIGINTs, SIGTERMs, and SIGHUPs and instead polls for them on a signal file descriptor.
When an event occurs on this file descriptor the signal received is determined and processed as follows:
SIGINT - Terminate the daemon SIGTERM - Terminate the daemon SIGHUP - Clear the window cache and point the LPC bus mapping back to flash
The daemon can be terminated for multiple reasons; invalid command line, unable to initialise, received SIGINT or SIGTERM, or because it received the kill D-Bus command.
On termination, the daemon clears the window cache and notifies the host that the active window has been closed, points the LPC bus mapping back to flash, clears the BMC_READY BMC event bit and frees all of its allocated resources.