/* * Copyright (C) 2017 The Android Open Source Project * * 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. */ #ifndef __CROS_EC_INCLUDE_APPLICATION_H #define __CROS_EC_INCLUDE_APPLICATION_H #include #ifdef __cplusplus extern "C" { #endif #ifndef __packed #define __packed __attribute__((packed)) #endif typedef const void * const __private; /* * Typical applications are independent tasks which are directed (or at least * influenced) by some off-chip program. Communications with the applications * are initiated by that off-chip Master and are routed to the application * using a variety of methods. */ /****************************************************************************/ /* * Datagram API: * * Nugget OS abstracts the bus protocol (SPI, USB, whatever) into two * unidirectional "datagram" transactions: * * - Read (the master wants data from the application) * - Write (the master sends data to the application) * * Each transaction consists of a four-byte Command from the Master, plus zero * or more data bytes either to (Read) or from (Write) the Master. * * The Command indicates the direction of data transfer, the application it * addresses, and various other parameters. The application is responsible for * providing (Read) or accepting (Write) the data bytes. * * Note: This interface was first used on the SPI bus, which allows for * simultaneous bidirectional data transfer. We limit this interface to * unidirectional transfers, because none of the other buses support that * feature. */ /****************************************************************************/ /* Application IDs */ /* These two App IDs shouldn't be changed or used for other purposes */ #define APP_ID_NUGGET 0x00 /* because we're selfish */ #define APP_ID_TPM_REGISTER_API 0xD4 /* mandated by the TCG */ /* * Other App IDs are defined here. It will help avoid confusion if you use only * the values from here and don't change them once they're set. But it's up to * you. I'm a comment, not a cop. */ #define APP_ID_AVB 0x01 #define APP_ID_KEYMASTER 0x02 #define APP_ID_WEAVER 0x03 #define APP_ID_PROTOBUF 0x04 #define APP_ID_IDENTITY 0x05 #define APP_ID_GSC_FACEAUTH 0x06 /* Fake apps used only for testing */ #define APP_ID_AVB_TEST 0x11 #define APP_ID_TRANSPORT_TEST 0x12 #define APP_ID_FACEAUTH_TEST 0x13 /* This app ID should only be used by tests. */ #define APP_ID_TEST 0xff /****************************************************************************/ /* Other command fields */ /* * The Command encoding is: * * Bits 31-24 Control flags (reserved) * Bits 23-16 Application ID * Bits 15-0 Parameters (application-specific) */ /* Control flag bits */ #define CMD_IS_READ 0x80000000 /* 1=Read, 0=Write */ /* All other control flags bits are reserved */ /* Extracting fields from a command */ #define GET_APP_ID(cmd) (((cmd) & 0x00ff0000) >> 16) #define GET_APP_PARAM(cmd) ((cmd) & 0x0000ffff) /* Specifying command fields */ #define CMD_ID(id) (((id) & 0x000000ff) << 16) #define CMD_PARAM(p) ((p) & 0x0000ffff) #define CMD_SET_PARAM(cmd, p) cmd = ((cmd & 0xffff0000) | (p & 0x0000ffff)) /****************************************************************************/ /* Data transfer */ /* * Functions of this type are invoked when the Master wants to read bytes from * an application. The app should parse the Command, copy up to max_tx_size * bytes into the tx_buffer provided, and return the number of bytes to send * back to the Master. * * This is called in interrupt context, so act quickly. * * The last arg is for internal use. Just ignore it. */ typedef uint32_t (read_from_app_fn_t)(uint32_t command, uint8_t *tx_buffer, uint32_t max_tx_bytes, __private priv); /* * Functions of this type are invoked when the Master has sent bytes to the * application. The app should parse the Command and copy or process the * expected number of bytes in the rx_buffer that the master has sent, up to * rx_num_bytes. * * NOTE: Due to a quirk of the Citadel hardware, up to four extra bytes from * the *next* transaction may be at the end of the rx_buffer. The application * should only poke at the bytes it expects to see and ignore any extras. * * This is called in interrupt context, so act quickly. * * The last arg is for internal use. Just ignore it. */ typedef void (write_to_app_fn_t)(uint32_t command, const uint8_t *rx_buffer, uint32_t num_rx_bytes, __private priv); /* * For apps that run asynchronously with little oversight, occasional * Read/Write operations may be all that's necessary. An app that intercepts * button presses, an accelerometer, or a fingerprint scanner can simply be * told to start or stop and will send interrupts to the Master when its * attention is required. * * Applications are free to define their own protcols and APIs using only the * functions and constants above (and at least one app does just that). * * An app that wishes to handle its messaging using only the components * described to this point would use the following macro to declare itself. */ /** * This registers an application that communicates using the Datagram API, * which deals only with the raw byte streams between Master (AP) and Slave * (application). * * The name and version values may be exported to the Master by Nugget OS, so * the Master can query what applications are available without blindly trying * them all to see what works. * * @param Id The Application ID, defined above * @param Name A human-readable string identifying the application * @param Version An app-specific uint32_t number, for compability purposes * @param From_fn A pointer to the app's read_from_app_fn_t handler * @param To_fn A pointer to the app's write_to_app_fn_t handler * @param Data App's private data */ #define DECLARE_APPLICATION_DATAGRAM(Id, Name, Version, From_fn, To_fn, Data) \ const struct app_info __keep CONCAT2(app_, Id) \ __attribute__((section(".rodata.app_info"))) \ = { .api = { .id = Id, \ .from_fn = From_fn, .to_fn = To_fn, \ .data = Data}, \ .version = Version, .name = Name } /****************************************************************************/ /* Transport API */ /* * Rather than handle unidirectonal datagrams themselves, many applications * want to implement a request/response behavior, where the Master tells the * app to do something and waits for it to finish and return the result. * * Seen from the AP's side, the application would be invoked using a blocking * function something like this: * * uint32_t call_application(uint8_t app_id, uint16_t app_param, * const uint8_t *args, uint16_t arg_len, * uint8_t *reply, uint16_t *reply_len); * * The request or response may be larger than one bus transaction, and the AP * may poll until the app finishes or wait for an interrupt before retrieving * the reply (there's no difference from app's point of view). * * With this API, the application is initially idle. Nugget OS will marshall * all the input from the Master before waking the application. The Application * then performs the requested operation and transititions to a "done" state. * The Master will retrieve the application status and any reply data from * Nugget OS, after which the application is ready to handle the next command. */ #define TRANSPORT_V0 0x0000 #define TRANSPORT_V1 0x0001 /* Command information for the transport protocol. */ struct transport_command_info { /* v1 fields */ uint16_t length; /* length of this message */ uint16_t version; /* max version used by master */ uint16_t crc; /* CRC of some command fields */ uint16_t reply_len_hint; /* max that the master will read */ } __packed; #define COMMAND_INFO_MIN_LENGTH 8 #define COMMAND_INFO_MAX_LENGTH 32 /* If more data needs to be sent, chain a new struct to the end of this one. It * will require its own CRC for data integrity and something to signify the * presence of the extra data. */ struct transport_status { /* v0 fields */ uint32_t status; /* status of the app */ uint16_t reply_len; /* length of available response data */ /* v1 fields */ uint16_t length; /* length of this message */ uint16_t version; /* max version used by slave */ uint16_t flags; /* space for more protocol state flags */ uint16_t crc; /* CRC of this status with crc set to 0 */ uint16_t reply_crc; /* CRC of the reply data */ } __packed; /* Valid range of lengths for the status message */ #define STATUS_MIN_LENGTH 0x10 #define STATUS_MAX_LENGTH 0xff /* Flags used in the status message */ #define STATUS_FLAG_WORKING 0x0001 /* added in v1 */ /* Pre-calculated CRCs for different status responses set in the interrupt * context where the CRC would otherwise not be calculated. */ #define STATUS_CRC_FOR_IDLE 0x54c1 #define STATUS_CRC_FOR_WORKING 0x2101 #define STATUS_CRC_FOR_ERROR_TOO_MUCH 0x97c0 /* * Applications that wish to use this transport API will need to declare a * private struct app_transport which Nugget OS can use to maintain the state: */ struct app_transport { void (*done_fn)(struct app_transport *); /* optional cleanup function */ /* Note: Any done_fn() is called in interrupt context. Be quick. */ uint8_t *const request; /* input data buffer */ uint8_t *const response; /* output data buffer */ const uint16_t max_request_len; /* input data buffer size */ const uint16_t max_response_len; /* output data buffer size */ /* The following are used for the incoming command. */ uint32_t command; /* from master */ union { struct transport_command_info info; uint8_t data[COMMAND_INFO_MAX_LENGTH]; /* space for future growth */ } command_info; /* extra info about the command */ uint16_t request_len; /* command data buffer size */ uint16_t response_idx; /* current index into response */ struct transport_status status[2]; /* current transport_status */ volatile uint8_t status_idx; /* index of active status */ }; /* * Note that request and response buffers are transferred as byte streams. * However, if they will eventually represent structs, the usual ABI alignment * requirements will be required. Until we've declared all applications structs * in a union, we will need to align the buffers manually. Use this to declare * the uint8_t buffers until then: */ #define __TRANSPORT_ALIGNED__ __attribute__((aligned(8))) /* * The application will need to provide a write_to_app_fn_t function that will * be invoked when a new request is ready to be processed. All command and data * parameters will already be present in the app's struct app_transport, so it * just needs to awaken the application task to do the work. * * When awakened, the application task must check that there were no errors in * the transmission of the request by calling this function. If it returns * true, the task should go back to sleep until the next request arrives. */ int request_is_invalid(struct app_transport *s); /* * When processing is finished, the app should call the app_reply() function to * return its status code and specify the length of any data it has placed into * the response buffer, and then it can go back to sleep until its next * invocation. CAUTION: The Master polls for app completion independently, so * it may immediately begin retrieving the results as soon as this function * is called *without* waiting for the Nugget OS app to go to sleep. */ void app_reply(struct app_transport *st, uint32_t status, uint16_t reply_len); /* Application status codes are uint32_t, but an enum is easier to read. */ enum app_status { /* A few values are common to all applications */ APP_SUCCESS = 0, APP_ERROR_BOGUS_ARGS, /* caller being stupid */ APP_ERROR_INTERNAL, /* application being stupid */ APP_ERROR_TOO_MUCH, /* caller sent too much data */ APP_ERROR_IO, /* problem sending or receiving data */ APP_ERROR_RPC, /* problem during RPC communication */ APP_ERROR_CHECKSUM, /* checksum failed, only used within protocol */ APP_ERROR_BUSY, /* the app is already working on a commnad */ APP_ERROR_TIMEOUT, /* the app took too long to respond */ APP_ERROR_NOT_READY, /* some required condition is not satisfied */ /* more? */ /* * Applications can define their own app-specific error codes. For example, * app_foobar.h can do: * * #define APP_ERROR_FOOBAR_BAZ (APP_SPECIFIC_ERROR + 0) * * Do not use (APP_SPECIFIC_ERROR + N) directly in your code, because the * error definition, firmware which generates it, and host code which * interprets it are all in different repos. You'll never be able to keep * the constants straight without using a #define or enum in your app's * header file that everyone can share. */ APP_SPECIFIC_ERROR = 0x20, /* "should be enough for anybody" */ /* For debugging, returning a line number might be helpful */ APP_LINE_NUMBER_BASE = 0x70000000, #define APP_ERROR_LINENO (APP_LINE_NUMBER_BASE + __LINE__) /* Bit 31 is reserved for internal use */ MAX_APP_STATUS = 0x7fffffff, }; /** * This registers an application that communicates using the Transport API. * * The name and version values may be exported to the Master by Nugget OS, so * the Master can query what applications are available without blindly trying * them all to see what works. * * @param Id The Application ID, defined above * @param Name A human-readable string identifying the application * @param Version An app-specific uint32_t number, for compability purposes * @param State A pointer to the app's struct app_transport * @param To_fn A pointer to the app's write_to_app_fn_t handler */ #define DECLARE_APPLICATION_TRANSPORT(Id, Name, Version, State, To_fn) \ const struct app_info __keep CONCAT2(app_, Id) \ __attribute__((section(".rodata.app_info"))) \ = { .api = { .id = Id, \ .from_fn = transaction_api_from_fn, \ .to_fn = transaction_api_to_fn, \ .data = &(const struct datagram_api) \ { .id = Id, .to_fn = To_fn, \ .data = State } }, \ .version = Version, .name = Name } /****************************************************************************/ /* Pay no attention to that man behind the curtain */ /* We'll allow 31 bits of application status. We need one bit for transport. */ #define APP_STATUS_IDLE 0x00000000 /* waiting for instructions */ #define APP_STATUS_DONE 0x80000000 /* finished, reply is ready */ #define APP_STATUS_CODE(res) ((res) & 0x7fffffff) /* actual status */ /* Datagram API needs this info */ struct datagram_api { uint8_t id; read_from_app_fn_t * const from_fn; write_to_app_fn_t * const to_fn; const void * const data; }; /* Here's the struct that keeps track of registered applications */ struct app_info { struct datagram_api api; uint32_t version; const char * const name; }; /* These handle the Transport API */ extern read_from_app_fn_t transaction_api_from_fn; extern write_to_app_fn_t transaction_api_to_fn; /* Command flags used internally by Transport API messages */ #define CMD_TRANSPORT 0x40000000 /* 1=Transport API message */ /* When CMD_TRANSPORT is set, the following bits have meaning */ #define CMD_IS_DATA 0x20000000 /* 1=data msg 0=status msg */ #define CMD_MORE_TO_COME 0x10000000 /* 1=continued 0=new */ #ifdef __cplusplus } #endif #endif /* __CROS_EC_INCLUDE_APPLICATION_H */