blob: 5a0a888480b5522eb2ae68a8b4bc11249d1ed590 [file] [log] [blame]
Miklos Balint9ecb24c2018-03-29 15:30:28 +02001/*
Kevin Pengf9a0eb02021-01-05 15:06:05 +08002 * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
Miklos Balint9ecb24c2018-03-29 15:30:28 +02003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8#ifndef __PSA_SERVICE_H__
9#define __PSA_SERVICE_H__
10
Jamie Fox520fb4d2019-06-13 14:27:21 +010011#include <stddef.h>
12#include <stdint.h>
13
Jamie Fox520fb4d2019-06-13 14:27:21 +010014#include "psa/client.h"
Ken Liu82e3eac2021-10-14 16:19:13 +080015#include "psa_config.h"
16#include "psa/error.h"
Shawn Shan038348e2021-09-08 17:11:04 +080017#include "psa/framework_feature.h"
Jamie Fox520fb4d2019-06-13 14:27:21 +010018
Miklos Balint9ecb24c2018-03-29 15:30:28 +020019#ifdef __cplusplus
20extern "C" {
21#endif
22
Edison Aib3e56962018-09-04 19:12:31 +080023/********************** PSA Secure Partition Macros and Types ****************/
24
Summer Qin4b1d03b2019-07-02 14:56:08 +080025/**
26 * A timeout value that requests a polling wait operation.
27 */
Miklos Balint9ecb24c2018-03-29 15:30:28 +020028#define PSA_POLL (0x00000000u)
Summer Qin4b1d03b2019-07-02 14:56:08 +080029
30/**
31 * A timeout value that requests a blocking wait operation.
32 */
Miklos Balint9ecb24c2018-03-29 15:30:28 +020033#define PSA_BLOCK (0x80000000u)
34
Summer Qin4b1d03b2019-07-02 14:56:08 +080035/**
36 * A mask value that includes all Secure Partition signals.
37 */
38#define PSA_WAIT_ANY (0xFFFFFFFFu)
Edison Aib3e56962018-09-04 19:12:31 +080039
Summer Qin4b1d03b2019-07-02 14:56:08 +080040/**
41 * The signal number for the Secure Partition doorbell.
42 */
Miklos Balint9ecb24c2018-03-29 15:30:28 +020043#define PSA_DOORBELL (0x00000008u)
44
45/* PSA message types */
Summer Qin4b1d03b2019-07-02 14:56:08 +080046/* An IPC message type that indicates a new connection. */
47#define PSA_IPC_CONNECT (-1)
48/* An IPC message type that indicates the end of a connection. */
49#define PSA_IPC_DISCONNECT (-2)
Edison Aib3e56962018-09-04 19:12:31 +080050
Kevin Peng9280ae92021-01-13 14:42:10 +080051/* FLIH return types */
52#define PSA_FLIH_NO_SIGNAL ((psa_flih_result_t) 0)
53#define PSA_FLIH_SIGNAL ((psa_flih_result_t) 1)
54
Edison Aib3e56962018-09-04 19:12:31 +080055/* Store a set of one or more Secure Partition signals */
Miklos Balint9ecb24c2018-03-29 15:30:28 +020056typedef uint32_t psa_signal_t;
57
Kevin Pengf9a0eb02021-01-05 15:06:05 +080058/* A type used to temporarily store a previous interrupt state. */
59typedef uint32_t psa_irq_status_t;
60
Kevin Peng9280ae92021-01-13 14:42:10 +080061/* The type of the return value from an FLIH function */
62typedef uint32_t psa_flih_result_t;
63
Miklos Balint9ecb24c2018-03-29 15:30:28 +020064/**
Edison Aib3e56962018-09-04 19:12:31 +080065 * Describe a message received by an RoT Service after calling \ref psa_get().
Miklos Balint9ecb24c2018-03-29 15:30:28 +020066 */
67typedef struct psa_msg_t {
Summer Qin4b1d03b2019-07-02 14:56:08 +080068 int32_t type; /* One of the following values:
Edison Aib3e56962018-09-04 19:12:31 +080069 * \ref PSA_IPC_CONNECT
Summer Qin4b1d03b2019-07-02 14:56:08 +080070 * >= 0
Edison Aib3e56962018-09-04 19:12:31 +080071 * \ref PSA_IPC_DISCONNECT
72 */
73 psa_handle_t handle; /* A reference generated by the SPM to the
74 * message returned by psa_get().
75 */
76 int32_t client_id; /* Partition ID of the sender of the message */
77 void *rhandle; /* Be useful for binding a connection to some
78 * application-specific data or function
79 * pointer within the RoT Service
80 * implementation.
81 */
82 size_t in_size[PSA_MAX_IOVEC]; /* Provide the size of each client input
83 * vector in bytes.
84 */
85 size_t out_size[PSA_MAX_IOVEC];/* Provide the size of each client output
86 * vector in bytes.
87 */
Miklos Balint9ecb24c2018-03-29 15:30:28 +020088} psa_msg_t;
89
Edison Aib3e56962018-09-04 19:12:31 +080090/************************* PSA Secure Partition API **************************/
Miklos Balint9ecb24c2018-03-29 15:30:28 +020091
92/**
Edison Aib3e56962018-09-04 19:12:31 +080093 * \brief Return the Secure Partition interrupt signals that have been asserted
94 * from a subset of signals provided by the caller.
Miklos Balint9ecb24c2018-03-29 15:30:28 +020095 *
Edison Aib3e56962018-09-04 19:12:31 +080096 * \param[in] signal_mask A set of signals to query. Signals that are not
97 * in this set will be ignored.
98 * \param[in] timeout Specify either blocking \ref PSA_BLOCK or
99 * polling \ref PSA_POLL operation.
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200100 *
Edison Aib3e56962018-09-04 19:12:31 +0800101 * \retval >0 At least one signal is asserted.
102 * \retval 0 No signals are asserted. This is only seen when
103 * a polling timeout is used.
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200104 */
Edison Aib3e56962018-09-04 19:12:31 +0800105psa_signal_t psa_wait(psa_signal_t signal_mask, uint32_t timeout);
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200106
107/**
Edison Aib3e56962018-09-04 19:12:31 +0800108 * \brief Retrieve the message which corresponds to a given RoT Service signal
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200109 * and remove the message from the RoT Service queue.
110 *
Edison Aib3e56962018-09-04 19:12:31 +0800111 * \param[in] signal The signal value for an asserted RoT Service.
112 * \param[out] msg Pointer to \ref psa_msg_t object for receiving
113 * the message.
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200114 *
Edison Aib3e56962018-09-04 19:12:31 +0800115 * \retval PSA_SUCCESS Success, *msg will contain the delivered
116 * message.
Summer Qin4b1d03b2019-07-02 14:56:08 +0800117 * \retval PSA_ERROR_DOES_NOT_EXIST Message could not be delivered.
118 * \retval "PROGRAMMER ERROR" The call is invalid because one or more of the
Edison Aib3e56962018-09-04 19:12:31 +0800119 * following are true:
120 * \arg signal has more than a single bit set.
121 * \arg signal does not correspond to an RoT Service.
122 * \arg The RoT Service signal is not currently
123 * asserted.
124 * \arg The msg pointer provided is not a valid memory
125 * reference.
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200126 */
Edison Aib3e56962018-09-04 19:12:31 +0800127psa_status_t psa_get(psa_signal_t signal, psa_msg_t *msg);
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200128
129/**
Edison Aib3e56962018-09-04 19:12:31 +0800130 * \brief Associate some RoT Service private data with a client connection.
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200131 *
Edison Aib3e56962018-09-04 19:12:31 +0800132 * \param[in] msg_handle Handle for the client's message.
133 * \param[in] rhandle Reverse handle allocated by the RoT Service.
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200134 *
Edison Aib3e56962018-09-04 19:12:31 +0800135 * \retval void Success, rhandle will be provided with all
136 * subsequent messages delivered on this
137 * connection.
Summer Qin4b1d03b2019-07-02 14:56:08 +0800138 * \retval "PROGRAMMER ERROR" msg_handle is invalid.
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200139 */
140void psa_set_rhandle(psa_handle_t msg_handle, void *rhandle);
141
142/**
Edison Aib3e56962018-09-04 19:12:31 +0800143 * \brief Read a message parameter or part of a message parameter from a client
144 * input vector.
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200145 *
Edison Aib3e56962018-09-04 19:12:31 +0800146 * \param[in] msg_handle Handle for the client's message.
147 * \param[in] invec_idx Index of the input vector to read from. Must be
148 * less than \ref PSA_MAX_IOVEC.
149 * \param[out] buffer Buffer in the Secure Partition to copy the
150 * requested data to.
151 * \param[in] num_bytes Maximum number of bytes to be read from the
152 * client input vector.
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200153 *
Edison Aib3e56962018-09-04 19:12:31 +0800154 * \retval >0 Number of bytes copied.
155 * \retval 0 There was no remaining data in this input
156 * vector.
Summer Qin4b1d03b2019-07-02 14:56:08 +0800157 * \retval "PROGRAMMER ERROR" The call is invalid, one or more of the
Edison Aib3e56962018-09-04 19:12:31 +0800158 * following are true:
159 * \arg msg_handle is invalid.
160 * \arg msg_handle does not refer to a
161 * \ref PSA_IPC_CALL message.
162 * \arg invec_idx is equal to or greater than
163 * \ref PSA_MAX_IOVEC.
164 * \arg the memory reference for buffer is invalid or
165 * not writable.
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200166 */
167size_t psa_read(psa_handle_t msg_handle, uint32_t invec_idx,
Edison Aib3e56962018-09-04 19:12:31 +0800168 void *buffer, size_t num_bytes);
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200169
170/**
Edison Aib3e56962018-09-04 19:12:31 +0800171 * \brief Skip over part of a client input vector.
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200172 *
Edison Aib3e56962018-09-04 19:12:31 +0800173 * \param[in] msg_handle Handle for the client's message.
174 * \param[in] invec_idx Index of input vector to skip from. Must be
175 * less than \ref PSA_MAX_IOVEC.
176 * \param[in] num_bytes Maximum number of bytes to skip in the client
177 * input vector.
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200178 *
Edison Aib3e56962018-09-04 19:12:31 +0800179 * \retval >0 Number of bytes skipped.
180 * \retval 0 There was no remaining data in this input
181 * vector.
Summer Qin4b1d03b2019-07-02 14:56:08 +0800182 * \retval "PROGRAMMER ERROR" The call is invalid, one or more of the
Edison Aib3e56962018-09-04 19:12:31 +0800183 * following are true:
184 * \arg msg_handle is invalid.
Summer Qin4b1d03b2019-07-02 14:56:08 +0800185 * \arg msg_handle does not refer to a request
186 * message.
Edison Aib3e56962018-09-04 19:12:31 +0800187 * \arg invec_idx is equal to or greater than
188 * \ref PSA_MAX_IOVEC.
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200189 */
190size_t psa_skip(psa_handle_t msg_handle, uint32_t invec_idx, size_t num_bytes);
191
192/**
Edison Aib3e56962018-09-04 19:12:31 +0800193 * \brief Write a message response to a client output vector.
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200194 *
Edison Aib3e56962018-09-04 19:12:31 +0800195 * \param[in] msg_handle Handle for the client's message.
196 * \param[out] outvec_idx Index of output vector in message to write to.
197 * Must be less than \ref PSA_MAX_IOVEC.
198 * \param[in] buffer Buffer with the data to write.
199 * \param[in] num_bytes Number of bytes to write to the client output
200 * vector.
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200201 *
Edison Aib3e56962018-09-04 19:12:31 +0800202 * \retval void Success
Summer Qin4b1d03b2019-07-02 14:56:08 +0800203 * \retval "PROGRAMMER ERROR" The call is invalid, one or more of the
Edison Aib3e56962018-09-04 19:12:31 +0800204 * following are true:
205 * \arg msg_handle is invalid.
Summer Qin4b1d03b2019-07-02 14:56:08 +0800206 * \arg msg_handle does not refer to a request
207 * message.
Edison Aib3e56962018-09-04 19:12:31 +0800208 * \arg outvec_idx is equal to or greater than
209 * \ref PSA_MAX_IOVEC.
210 * \arg The memory reference for buffer is invalid.
211 * \arg The call attempts to write data past the end
212 * of the client output vector.
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200213 */
214void psa_write(psa_handle_t msg_handle, uint32_t outvec_idx,
Edison Aib3e56962018-09-04 19:12:31 +0800215 const void *buffer, size_t num_bytes);
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200216
217/**
Edison Aib3e56962018-09-04 19:12:31 +0800218 * \brief Complete handling of a specific message and unblock the client.
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200219 *
Edison Aib3e56962018-09-04 19:12:31 +0800220 * \param[in] msg_handle Handle for the client's message.
221 * \param[in] status Message result value to be reported to the
222 * client.
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200223 *
Edison Aib3e56962018-09-04 19:12:31 +0800224 * \retval void Success.
Summer Qin4b1d03b2019-07-02 14:56:08 +0800225 * \retval "PROGRAMMER ERROR" The call is invalid, one or more of the
Edison Aib3e56962018-09-04 19:12:31 +0800226 * following are true:
227 * \arg msg_handle is invalid.
228 * \arg An invalid status code is specified for the
229 * type of message.
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200230 */
Edison Aib3e56962018-09-04 19:12:31 +0800231void psa_reply(psa_handle_t msg_handle, psa_status_t status);
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200232
233/**
Edison Aib3e56962018-09-04 19:12:31 +0800234 * \brief Send a PSA_DOORBELL signal to a specific Secure Partition.
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200235 *
Edison Aib3e56962018-09-04 19:12:31 +0800236 * \param[in] partition_id Secure Partition ID of the target partition.
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200237 *
Edison Aib3e56962018-09-04 19:12:31 +0800238 * \retval void Success.
Summer Qin4b1d03b2019-07-02 14:56:08 +0800239 * \retval "PROGRAMMER ERROR" partition_id does not correspond to a Secure
Edison Aib3e56962018-09-04 19:12:31 +0800240 * Partition.
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200241 */
242void psa_notify(int32_t partition_id);
243
244/**
Edison Aib3e56962018-09-04 19:12:31 +0800245 * \brief Clear the PSA_DOORBELL signal.
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200246 *
Edison Aib3e56962018-09-04 19:12:31 +0800247 * \retval void Success.
Summer Qin4b1d03b2019-07-02 14:56:08 +0800248 * \retval "PROGRAMMER ERROR" The Secure Partition's doorbell signal is not
Edison Aib3e56962018-09-04 19:12:31 +0800249 * currently asserted.
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200250 */
251void psa_clear(void);
252
253/**
Edison Aib3e56962018-09-04 19:12:31 +0800254 * \brief Inform the SPM that an interrupt has been handled (end of interrupt).
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200255 *
Edison Aib3e56962018-09-04 19:12:31 +0800256 * \param[in] irq_signal The interrupt signal that has been processed.
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200257 *
Edison Aib3e56962018-09-04 19:12:31 +0800258 * \retval void Success.
Summer Qin4b1d03b2019-07-02 14:56:08 +0800259 * \retval "PROGRAMMER ERROR" The call is invalid, one or more of the
Edison Aib3e56962018-09-04 19:12:31 +0800260 * following are true:
261 * \arg irq_signal is not an interrupt signal.
262 * \arg irq_signal indicates more than one signal.
263 * \arg irq_signal is not currently asserted.
Kevin Peng9280ae92021-01-13 14:42:10 +0800264 * \arg The interrupt is not using SLIH.
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200265 */
Edison Aib3e56962018-09-04 19:12:31 +0800266void psa_eoi(psa_signal_t irq_signal);
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200267
Summer Qin4b1d03b2019-07-02 14:56:08 +0800268/**
269 * \brief Terminate execution within the calling Secure Partition and will not
270 * return.
271 *
272 * \retval "Does not return"
273 */
274void psa_panic(void);
275
Kevin Pengf9a0eb02021-01-05 15:06:05 +0800276/**
277 * \brief Enable an interrupt.
278 *
279 * \param[in] irq_signal The signal for the interrupt to be enabled.
280 * This must have a single bit set, which must be the
281 * signal value for an interrupt in the calling Secure
282 * Partition.
283 *
284 * \retval void
285 * \retval "PROGRAMMER ERROR" If one or more of the following are true:
Kevin Peng9280ae92021-01-13 14:42:10 +0800286 * \arg \a irq_signal is not an interrupt signal.
287 * \arg \a irq_signal indicates more than one signal.
Kevin Pengf9a0eb02021-01-05 15:06:05 +0800288 */
289void psa_irq_enable(psa_signal_t irq_signal);
290
291/**
292 * \brief Disable an interrupt and return the status of the interrupt prior to
293 * being disabled by this call.
294 *
295 * \param[in] irq_signal The signal for the interrupt to be disabled.
296 * This must have a single bit set, which must be the
297 * signal value for an interrupt in the calling Secure
298 * Partition.
299 *
300 * \retval 0 The interrupt was disabled prior to this call.
301 * 1 The interrupt was enabled prior to this call.
302 * \retval "PROGRAMMER ERROR" If one or more of the following are true:
Kevin Peng9280ae92021-01-13 14:42:10 +0800303 * \arg \a irq_signal is not an interrupt signal.
304 * \arg \a irq_signal indicates more than one signal.
Kevin Pengf9a0eb02021-01-05 15:06:05 +0800305 *
306 * \note The current implementation always return 1. Do not use the return.
307 */
308psa_irq_status_t psa_irq_disable(psa_signal_t irq_signal);
309
Kevin Peng9280ae92021-01-13 14:42:10 +0800310/**
311 * \brief Reset the signal for an interrupt that is using FLIH handling.
312 *
313 * \param[in] irq_signal The interrupt signal to be reset.
314 * This must have a single bit set, corresponding to a
315 * currently asserted signal for an interrupt that is
316 * defined to use FLIH handling.
317 *
318 * \retval void
319 * \retval "Programmer Error" if one or more of the following are true:
320 * \arg \a irq_signal is not a signal for an interrupt
321 * that is specified with FLIH handling in the Secure
322 * Partition manifest.
323 * \arg \a irq_signal indicates more than one signal.
324 * \arg \a irq_signal is not currently asserted.
325 */
326void psa_reset_signal(psa_signal_t irq_signal);
327
Shawn Shan038348e2021-09-08 17:11:04 +0800328#if PSA_FRAMEWORK_HAS_MM_IOVEC
329
330/**
331 * \brief Map a client input vector for direct access by a Secure Partition RoT
332 * Service.
333 *
334 * \param[in] msg_handle Handle for the client's message.
335 * \param[in] invec_idx Index of input vector to map. Must be
336 * less than \ref PSA_MAX_IOVEC.
337 *
338 * \retval A pointer to the input vector data.
339 * \retval "PROGRAMMER ERROR" The call is invalid, one or more of the
340 * following are true:
341 * \arg MM-IOVEC has not been enabled for the RoT
342 * Service that received the message.
343 * \arg msg_handle is invalid.
344 * \arg msg_handle does not refer to a request
345 * message.
346 * \arg invec_idx is equal to or greater than
347 * \ref PSA_MAX_IOVEC.
348 * \arg The input vector has length zero.
349 * \arg The input vector has already been mapped using
350 * psa_map_invec().
351 * \arg The input vector has already been accessed
352 * using psa_read() or psa_skip().
353 */
354const void *psa_map_invec(psa_handle_t msg_handle, uint32_t invec_idx);
355
356/**
357 * \brief Unmap a previously mapped client input vector from a Secure Partition
358 * RoT Service.
359 *
360 * \param[in] msg_handle Handle for the client's message.
361 * \param[in] invec_idx Index of input vector to map. Must be
362 * less than \ref PSA_MAX_IOVEC.
363 *
364 * \retval void
365 * \retval "PROGRAMMER ERROR" The call is invalid, one or more of the
366 * following are true:
367 * \arg msg_handle is invalid.
368 * \arg msg_handle does not refer to a request
369 * message.
370 * \arg invec_idx is equal to or greater than
371 * \ref PSA_MAX_IOVEC.
372 * \arg The input vector has not been mapped by a call
373 * to psa_map_invec().
374 * \arg The input vector has already been unmapped by
375 * a call to psa_unmap_invec().
376 */
377void psa_unmap_invec(psa_handle_t msg_handle, uint32_t invec_idx);
378
379/**
380 * \brief Map a client output vector for direct access by a Secure Partition RoT
381 * Service.
382 *
383 * \param[in] msg_handle Handle for the client's message.
384 * \param[in] outvec_idx Index of output vector to map. Must be
385 * less than \ref PSA_MAX_IOVEC.
386 *
387 * \retval A pointer to the output vector data.
388 * \retval "PROGRAMMER ERROR" The call is invalid, one or more of the
389 * following are true:
390 * \arg MM-IOVEC has not been enabled for the RoT
391 * Service that received the message.
392 * \arg msg_handle is invalid.
393 * \arg msg_handle does not refer to a request
394 * message.
395 * \arg outvec_idx is equal to or greater than
396 * \ref PSA_MAX_IOVEC.
397 * \arg The output vector has length zero.
398 * \arg The output vector has already been mapped
399 * using psa_map_outvec().
400 * \arg The output vector has already been accessed
401 * using psa_write().
402 */
403void *psa_map_outvec(psa_handle_t msg_handle, uint32_t outvec_idx);
404
405/**
406 * \brief Unmap a previously mapped client output vector from a Secure Partition
407 * RoT Service.
408 *
409 * \param[in] msg_handle Handle for the client's message.
410 * \param[in] outvec_idx Index of output vector to map. Must be
411 * less than \ref PSA_MAX_IOVEC.
412 * \param[in] len The number of bytes written to the output
413 * vector. This must be less than or equal to the
414 * size of the output vector.
415 *
416 * \retval void
417 * \retval "PROGRAMMER ERROR" The call is invalid, one or more of the
418 * following are true:
419 * \arg msg_handle is invalid.
420 * \arg msg_handle does not refer to a request
421 * message.
422 * \arg outvec_idx is equal to or greater than
423 * \ref PSA_MAX_IOVEC.
424 * \arg The output vector has not been mapped by a
425 * call to psa_map_outvec().
426 * \arg The output vector has already been unmapped by
427 * a call to psa_unmap_outvec().
428 */
429void psa_unmap_outvec(psa_handle_t msg_handle, uint32_t outvec_idx, size_t len);
430
431#endif /* PSA_FRAMEWORK_HAS_MM_IOVEC */
432
Miklos Balint9ecb24c2018-03-29 15:30:28 +0200433#ifdef __cplusplus
434}
435#endif
436
437#endif /* __PSA_SERVICE_H__ */