123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268 |
- Introduction
- ============
- The PIL (Peripheral Image Loader) driver loads peripheral images into memory
- and interfaces with the Peripheral Authentication Service (PAS) to
- authenticate and reset peripherals embedded in the SoC.
- The PAS could either be running under secure mode in the application
- processor (secure boot support) or be running as a non-secure kernel driver
- (non-secure boot support).
- The PIL driver also does housekeeping to handle cases where more than one
- client driver is using the same peripheral.
- Some examples of peripherals are modem, DSP and sensors.
- Hardware description
- ====================
- The memory used by the peripherals for code and data storage will be
- accessible as normal memory to the application processor.
- The non-secure code (Linux kernel) will have read/write permissions to the
- peripheral memory by default.
- The PAS will have access to a MPU (memory protection unit) that can lock away
- the pages of memory from the Linux kernel. It will also have access to
- registers that can reset each peripheral.
- Software description
- ====================
- The PAS provides the following three APIs:
- * Init image - Takes as input the peripheral id and firmware metadata and
- returns a status indicating the authenticity of the firmware metadata. The
- firmware metadata consists of a standard ELF32 header followed by a program
- header table and an optional blob of data used to authenticate the metadata
- and the rest of the firmware.
- * Verify segment - Takes as input the firmware segment id and the length of
- the segment. Authenticates whatever amount (specified by the "length"
- parameter) of the firmware segment that has been loaded and removes
- non-secure mode read/write permissions for the pages belonging to the
- firmware segment. Allows multiple calls for the same firmware segment to
- allow partial loading and authentication.
- * Auth and Reset - Verifies all the necessary firmware segments have been
- loaded and authenticated and then resets the peripheral.
- The user space is expected to provide the firmware metadata and firmware
- segments as separate files on persistent storage. See "Interface" section for
- further details.
- The PIL driver will use the request_firmware API provided by the Linux kernel
- to read the firmware and firmware metadata from persistent storage.
- When a client driver requests for a peripheral to be enabled, the PIL driver
- increments the reference count for that peripheral, loads the firmware
- metadata and calls the PAS Init Image API that initializes the authentication
- state machine using the firmware metadata.
- If the initialization succeeds, the PIL driver loads the appropriate firmware
- segments into their respective memory locations and call the PAS Verify
- segment API on each of the loaded segments to authenticate and lock it.
- After all the firmware segments have been successfully loaded and
- authenticated, the PAS Auth and Reset API is called to reset the peripheral
- and initiate its boot sequence.
- A peripheral enable request to the PIL driver will block until it succeeds
- (or fails) to initiate the peripheral boot sequence but will NOT block until
- the peripheral is ready. It is not possible to block until a peripheral is
- ready since the semantics of "ready" is subjective to the caller.
- The PIL driver will maintain a reference count for each of the peripherals.
- So, if a peripheral is already under use and another client driver requests
- for the peripheral to be enabled, the PIL driver will immediately return a
- value to indicate success.
- When all the client drivers of a particular peripheral no longer need the
- peripheral and the reference count reaches zero, the PIL driver can cleanly
- shut down the peripheral. Since a lot of drivers in their current state can't
- handle a peripheral restart, the PIL driver will never let the reference
- count go back to zero.
- All information about a peripheral, like firmware filenames, peripheral ID
- passed to PAS, etc, will be hard coded in the PIL driver.
- All the PIL APIs will execute in the context of the caller. This includes
- calls from the PIL driver to the PAS driver. The PAS driver might decide to
- switch into secure mode from a separate workqueue or in the same context as
- the caller, but that shouldn't have any implications for the PIL API callers
- since all the PIL APIs are blocking calls.
- Dependencies:
- -------------
- * Firmware class (CONFIG_FW_LOADER) for using the request_firmware API to
- load firmware from persistent storage.
- * PAS to authenticate firmware and bring a peripheral out of reset.
- Error cases:
- ------------
- The PIL driver could fail to enable a peripheral for several reasons like not
- having enough memory to load firmware and metadata, being unable to
- communicate with the PAS, the PAS returning with an error, etc. For all
- possible error cases, the PIL driver does not perform any retries and returns
- an appropriate error code. The client drivers should always check for success
- before trying to access the peripheral.
- Design
- ======
- Design goals:
- -------------
- * The PIL driver must be agnostic to the actual format and method used to
- authenticate the firmware.
- * Allow for future expansion to support demand loading of parts of firmware
- for each peripheral.
- * Move most of the work into the preprocessing/building stage of the firmware.
- * Provide an API to the client drivers that absolves them from having to know
- the structure or names of the firmware in persistent storage.
- * Handle multiple client drivers wanting to enable the same peripheral.
- Design reasons:
- ---------------
- The user space is expected to provide the firmware metadata and segments as
- separate files for the following reasons:
- * Don't need to load the whole ELF file if the authentication info is
- invalid.
- * Works better during low memory conditions since the amount of memory used
- at any given instant when loading one segment at a time is smaller than
- loading the whole ELF file.
- * Since an ELF segment in memory can be much bigger than on file, having a
- flat binary would waste a lot of space due to zero-fills.
- * Allows for future enhancements to the loading procedure.
- Design tradeoffs:
- -----------------
- * With appropriate changes to the request_firmware API, the firmware blobs
- could be directly loaded into the right memory location. But due to the
- additional work and community approval that would be needed for modifying
- the request_firmware API, we load the firmware blobs into kernel memory and
- then copy them into the appropriate locations.
- Alternate designs:
- ------------------
- One of the alternate designs that were considered required the firmware to be
- a flat binary. Although this design would simplify the PIL driver, it would
- result in the waste of a lot of persistent storage space (due to large
- zero-fills), prevent demand loading of segments in the future and use a lot
- more memory while loading the firmware.
- Software layering:
- ------------------
- The peripheral authentication, reset and shutdown implementation is factored
- away into a Peripheral Authentication Service driver to allow the PIL driver
- to be agnostic of secure vs. non-secure boot and the mechanisms needed for
- communicating with any code that might be running in secure mode.
- Power Management
- ================
- Some of the peripherals might support being turned off when not in use.
- Support for this might be disabled in the initial implementation of the PIL
- driver since many of the existing drivers can not handle peripheral restart.
- SMP/multi-core
- ==============
- Will use mutexes to protected data that might be shared (reference count,
- etc).
- Security
- ========
- The PIL driver must validate the physical memory addresses specified in the
- ELF and program header table before loading firmware segments to make sure
- it's not overwriting any memory used by the kernel and possibly PMEM regions
- (if it can be done without being an ugly hack). The PIL driver might need to
- maintain a white list or black list of physical memory address ranges to
- perform the address validation.
- Performance
- ===========
- As mentioned in the design section, the loading of firmware segments is not
- optimal and has room for improvement.
- Interface
- =========
- In kernel APIs:
- void * pil_get(char *peripheral_name)
- - Enables (if not already enabled) a peripheral and returns a handle
- that can be used to disable the peripheral at a later time. If
- peripheral can't be enabled successfully, then returns an error
- (use IS_ERR) indicating the reason.
- void pil_put(void *peripheral_handle)
- - Inform PIL that this client no longer needs the peripheral to be
- active. Does not necessarily mean that the peripheral would be
- disabled or powered off.
- User space APIs:
- All firmware must be located in the path that is expected by the hotplug (or
- compatible) daemon. A hotplug (or compatible) daemon should be running and be
- able to handle events from the kernel requesting for a firmware file.
- The basename of the firmware files will depend on the peripheral. For a given
- peripheral, the metadata filename should end with a ".mdt" and the firmware
- segment files should end with ".bXX" where XX denotes the index of the
- firmware segment starting from 0.
- Android hotplug compatible daemon expects the firmware files to be under
- /etc/firmware.
- Driver parameters
- =================
- No module or kernel command line parameters supported.
- Config options
- ==============
- This driver is enabled using the MSM_PIL kernel config option and will
- depend on the CONFIG_FW_LOADER being available.
- Dependencies
- ============
- Depends on firmware class module for the request_firmware API.
- Interacts with the PAS to authenticate the firmware and to initiate the boot
- sequence of a peripheral.
- Doesn't communicate with other processors since the secure code, if any, will
- be running on the application processor cores.
- User space utilities
- ====================
- None.
- Other
- =====
- The firmware_class driver might be changed in the future to directly load the
- firmware into memory locations provided by the caller of request_firmware().
- Known issues
- ============
- Since support for cleanly shutting down peripherals is yet to be added, the
- reference count of peripherals will never be allowed to go to zero once it
- becomes non-zero.
- To do
- =====
- * Add support for turning off peripherals when they are not in use.
- * Modify request_firmware() to directly copy firmware blobs into the
- appropriate memory locations.
- * Add support for demand loading of firmware segments.
- * Add support for forced peripheral restarts.
|