LCOV - code coverage report
Current view: top level - libflash/test - mbox-server.c (source / functions) Hit Total Coverage
Test: skiboot.info Lines: 239 287 83.3 %
Date: 2024-01-02 21:04:04 Functions: 21 21 100.0 %
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
       2                 :            : /* Copyright 2017 IBM Corp. */
       3                 :            : 
       4                 :            : #include <stdio.h>
       5                 :            : #include <stdlib.h>
       6                 :            : #include <stdint.h>
       7                 :            : #include <string.h>
       8                 :            : #include <stdarg.h>
       9                 :            : #include <inttypes.h>
      10                 :            : 
      11                 :            : #include <sys/mman.h> /* for mprotect() */
      12                 :            : 
      13                 :            : #define pr_fmt(fmt) "MBOX-SERVER: " fmt
      14                 :            : #include "skiboot.h"
      15                 :            : #include "opal-api.h"
      16                 :            : 
      17                 :            : #include "mbox-server.h"
      18                 :            : #include "stubs.h"
      19                 :            : 
      20                 :            : #define ERASE_GRANULE 0x100
      21                 :            : 
      22                 :            : #define LPC_BLOCKS 256
      23                 :            : 
      24                 :            : #define __unused          __attribute__((unused))
      25                 :            : 
      26                 :            : enum win_type {
      27                 :            :         WIN_CLOSED,
      28                 :            :         WIN_READ,
      29                 :            :         WIN_WRITE
      30                 :            : };
      31                 :            : 
      32                 :            : typedef void (*mbox_data_cb)(struct bmc_mbox_msg *msg, void *priv);
      33                 :            : typedef void (*mbox_attn_cb)(uint8_t reg, void *priv);
      34                 :            : 
      35                 :            : struct {
      36                 :            :         mbox_data_cb fn;
      37                 :            :         void *cb_data;
      38                 :            :         struct bmc_mbox_msg *msg;
      39                 :            :         mbox_attn_cb attn;
      40                 :            :         void *cb_attn;
      41                 :            : } mbox_data;
      42                 :            : 
      43                 :            : static struct {
      44                 :            :         int api;
      45                 :            :         bool reset;
      46                 :            : 
      47                 :            :         void *lpc_base;
      48                 :            :         size_t lpc_size;
      49                 :            : 
      50                 :            :         uint8_t attn_reg;
      51                 :            : 
      52                 :            :         uint32_t block_shift;
      53                 :            :         uint32_t erase_granule;
      54                 :            : 
      55                 :            :         uint16_t def_read_win;  /* default window size in blocks */
      56                 :            :         uint16_t def_write_win;
      57                 :            : 
      58                 :            :         uint16_t max_read_win; /* max window size in blocks */
      59                 :            :         uint16_t max_write_win;
      60                 :            : 
      61                 :            :         enum win_type win_type;
      62                 :            :         uint32_t win_base;
      63                 :            :         uint32_t win_size;
      64                 :            :         bool win_dirty;
      65                 :            : } server_state;
      66                 :            : 
      67                 :            : 
      68                 :   28670397 : static bool check_window(uint32_t pos, uint32_t size)
      69                 :            : {
      70                 :            :         /* If size is zero then all is well */
      71                 :   28670397 :         if (size == 0)
      72                 :         24 :                 return true;
      73                 :            : 
      74                 :   28670373 :         if (server_state.api == 1) {
      75                 :            :                 /*
      76                 :            :                  * Can actually be stricter in v1 because pos is relative to
      77                 :            :                  * flash not window
      78                 :            :                  */
      79                 :     104244 :                 if (pos < server_state.win_base ||
      80                 :     104244 :                                 pos + size > server_state.win_base + server_state.win_size) {
      81                 :          0 :                         fprintf(stderr, "pos: 0x%08x size: 0x%08x aren't in active window\n",
      82                 :            :                                         pos, size);
      83                 :          0 :                         fprintf(stderr, "window pos: 0x%08x window size: 0x%08x\n",
      84                 :            :                                         server_state.win_base, server_state.win_size);
      85                 :          0 :                         return false;
      86                 :            :                 }
      87                 :            :         } else {
      88                 :   28566129 :                 if (pos + size > server_state.win_base + server_state.win_size)
      89                 :          0 :                         return false;
      90                 :            :         }
      91                 :   28670373 :         return true;
      92                 :            : }
      93                 :            : 
      94                 :            : /* skiboot test stubs */
      95                 :            : int64_t lpc_read(enum OpalLPCAddressType __unused addr_type, uint32_t addr,
      96                 :            :                  uint32_t *data, uint32_t sz);
      97                 :   22434105 : int64_t lpc_read(enum OpalLPCAddressType __unused addr_type, uint32_t addr,
      98                 :            :                  uint32_t *data, uint32_t sz)
      99                 :            : {
     100                 :            :         /* Let it read from a write window... Spec says it ok! */
     101                 :   22434105 :         if (!check_window(addr, sz) || server_state.win_type == WIN_CLOSED)
     102                 :          0 :                 return 1;
     103                 :            : 
     104                 :   22434105 :         switch (sz) {
     105                 :        308 :         case 1:
     106                 :        308 :                 *(uint8_t *)data = *(uint8_t *)(server_state.lpc_base + addr);
     107                 :        308 :                 break;
     108                 :          0 :         case 2:
     109                 :          0 :                 *(uint16_t *)data = be16_to_cpu(*(uint16_t *)(server_state.lpc_base + addr));
     110                 :          0 :                 break;
     111                 :   22433797 :         case 4:
     112                 :   22433797 :                 *(uint32_t *)data = be32_to_cpu(*(uint32_t *)(server_state.lpc_base + addr));
     113                 :   22433797 :                 break;
     114                 :          0 :         default:
     115                 :          0 :                 prerror("Invalid data size %d\n", sz);
     116                 :          0 :                 return 1;
     117                 :            :         }
     118                 :   22434105 :         return 0;
     119                 :            : }
     120                 :            : 
     121                 :            : int64_t lpc_write(enum OpalLPCAddressType __unused addr_type, uint32_t addr,
     122                 :            :                   uint32_t data, uint32_t sz);
     123                 :    6236172 : int64_t lpc_write(enum OpalLPCAddressType __unused addr_type, uint32_t addr,
     124                 :            :                   uint32_t data, uint32_t sz)
     125                 :            : {
     126                 :    6236172 :         if (!check_window(addr, sz) || server_state.win_type != WIN_WRITE)
     127                 :          0 :                 return 1;
     128                 :    6236172 :         switch (sz) {
     129                 :          0 :         case 1:
     130                 :          0 :                 *(uint8_t *)(server_state.lpc_base + addr) = data;
     131                 :          0 :                 break;
     132                 :          0 :         case 2:
     133                 :          0 :                 *(uint16_t *)(server_state.lpc_base + addr) = cpu_to_be16(data);
     134                 :          0 :                 break;
     135                 :    6236172 :         case 4:
     136                 :    6236172 :                 *(uint32_t *)(server_state.lpc_base + addr) = cpu_to_be32(data);
     137                 :    6236172 :                 break;
     138                 :          0 :         default:
     139                 :          0 :                 prerror("Invalid data size %d\n", sz);
     140                 :          0 :                 return 1;
     141                 :            :         }
     142                 :    6236172 :         return 0;
     143                 :            : }
     144                 :            : 
     145                 :            : int64_t lpc_fw_read(uint32_t off, void *buf, uint32_t len);
     146                 :        659 : int64_t lpc_fw_read(uint32_t off, void *buf, uint32_t len)
     147                 :            : {
     148                 :            :         int rc;
     149                 :            : 
     150                 :   22434764 :         while (len) {
     151                 :            :                 uint32_t chunk;
     152                 :            :                 uint32_t dat;
     153                 :            : 
     154                 :            :                 /* XXX: make this read until it's aligned */
     155                 :   22434105 :                 if (len > 3 && !(off & 3)) {
     156                 :   22433797 :                         rc = lpc_read(OPAL_LPC_FW, off, &dat, 4);
     157                 :   22433797 :                         if (!rc) {
     158                 :            :                                 /*
     159                 :            :                                  * lpc_read swaps to CPU endian but it's not
     160                 :            :                                  * really a 32-bit value, so convert back.
     161                 :            :                                  */
     162                 :   22433797 :                                 *(__be32 *)buf = cpu_to_be32(dat);
     163                 :            :                         }
     164                 :   22433797 :                         chunk = 4;
     165                 :            :                 } else {
     166                 :        308 :                         rc = lpc_read(OPAL_LPC_FW, off, &dat, 1);
     167                 :        308 :                         if (!rc)
     168                 :        308 :                                 *(uint8_t *)buf = dat;
     169                 :        308 :                         chunk = 1;
     170                 :            :                 }
     171                 :   22434105 :                 if (rc)
     172                 :          0 :                         return rc;
     173                 :            : 
     174                 :   22434105 :                 len -= chunk;
     175                 :   22434105 :                 off += chunk;
     176                 :   22434105 :                 buf += chunk;
     177                 :            :         }
     178                 :            : 
     179                 :        659 :         return 0;
     180                 :            : }
     181                 :            : 
     182                 :            : int64_t lpc_fw_write(uint32_t off, const void *buf, uint32_t len);
     183                 :         96 : int64_t lpc_fw_write(uint32_t off, const void *buf, uint32_t len)
     184                 :            : {
     185                 :            :         int rc;
     186                 :            : 
     187                 :    6236268 :         while (len) {
     188                 :            :                 uint32_t chunk;
     189                 :            : 
     190                 :    6236172 :                 if (len > 3 && !(off & 3)) {
     191                 :            :                         /* endian swap: see lpc_window_write */
     192                 :    6236172 :                         uint32_t dat = be32_to_cpu(*(__be32 *)buf);
     193                 :            : 
     194                 :    6236172 :                         rc = lpc_write(OPAL_LPC_FW, off, dat, 4);
     195                 :    6236172 :                         chunk = 4;
     196                 :            :                 } else {
     197                 :          0 :                         uint8_t dat = *(uint8_t *)buf;
     198                 :            : 
     199                 :          0 :                         rc = lpc_write(OPAL_LPC_FW, off, dat, 1);
     200                 :          0 :                         chunk = 1;
     201                 :            :                 }
     202                 :    6236172 :                 if (rc)
     203                 :          0 :                         return rc;
     204                 :            : 
     205                 :    6236172 :                 len -= chunk;
     206                 :    6236172 :                 off += chunk;
     207                 :    6236172 :                 buf += chunk;
     208                 :            :         }
     209                 :            : 
     210                 :         96 :         return 0;
     211                 :            : }
     212                 :            : 
     213                 :          4 : int bmc_mbox_register_attn(mbox_attn_cb handler, void *drv_data)
     214                 :            : {
     215                 :          4 :         mbox_data.attn = handler;
     216                 :          4 :         mbox_data.cb_attn = drv_data;
     217                 :            : 
     218                 :          4 :         return 0;
     219                 :            : }
     220                 :            : 
     221                 :          7 : uint8_t bmc_mbox_get_attn_reg(void)
     222                 :            : {
     223                 :          7 :         return server_state.attn_reg;
     224                 :            : }
     225                 :            : 
     226                 :          4 : int bmc_mbox_register_callback(mbox_data_cb handler, void *drv_data)
     227                 :            : {
     228                 :          4 :         mbox_data.fn = handler;
     229                 :          4 :         mbox_data.cb_data = drv_data;
     230                 :            : 
     231                 :          4 :         return 0;
     232                 :            : }
     233                 :            : 
     234                 :        734 : static int close_window(bool check)
     235                 :            : {
     236                 :            :         /*
     237                 :            :          * This isn't strictly prohibited and some daemons let you close
     238                 :            :          * windows even if none are open.
     239                 :            :          * I've made the test fail because closing with no windows open is
     240                 :            :          * a sign that something 'interesting' has happened.
     241                 :            :          * You should investigate why
     242                 :            :          *
     243                 :            :          * If check is false it is because we just want to do the logic
     244                 :            :          * because open window has been called - you can open a window
     245                 :            :          * over a closed window obviously
     246                 :            :          */
     247                 :        734 :         if (check && server_state.win_type == WIN_CLOSED)
     248                 :          0 :                 return MBOX_R_PARAM_ERROR;
     249                 :            : 
     250                 :        734 :         server_state.win_type = WIN_CLOSED;
     251                 :        734 :         mprotect(server_state.lpc_base, server_state.lpc_size, PROT_NONE);
     252                 :            : 
     253                 :        734 :         return MBOX_R_SUCCESS;
     254                 :            : }
     255                 :            : 
     256                 :        120 : static int do_dirty(uint32_t pos, uint32_t size)
     257                 :            : {
     258                 :        120 :         pos <<= server_state.block_shift;
     259                 :        120 :         if (server_state.api > 1)
     260                 :         72 :                 size <<= server_state.block_shift;
     261                 :        120 :         if (!check_window(pos, size)) {
     262                 :          0 :                 prlog(PR_ERR, "Trying to dirty not in open window range\n");
     263                 :          0 :                 return MBOX_R_PARAM_ERROR;
     264                 :            :         }
     265                 :        120 :         if (server_state.win_type != WIN_WRITE) {
     266                 :          0 :                 prlog(PR_ERR, "Trying to dirty not write window\n");
     267                 :          0 :                 return MBOX_R_PARAM_ERROR;
     268                 :            :         }
     269                 :            : 
     270                 :            :         /* Thats about all actually */
     271                 :        120 :         return MBOX_R_SUCCESS;
     272                 :            : }
     273                 :            : 
     274                 :        944 : void check_timers(bool __unused unused)
     275                 :            : {
     276                 :            :         /* now that we've handled the message, holla-back */
     277                 :        944 :         if (mbox_data.msg) {
     278                 :        944 :                 mbox_data.fn(mbox_data.msg, mbox_data.cb_data);
     279                 :        944 :                 mbox_data.msg = NULL;
     280                 :            :         }
     281                 :        944 : }
     282                 :            : 
     283                 :        735 : static int open_window(struct bmc_mbox_msg *msg, bool write, u32 offset, u32 size)
     284                 :            : {
     285                 :        735 :         int max_size = server_state.max_read_win << server_state.block_shift;
     286                 :            :         //int win_size = server_state.def_read_win;
     287                 :        735 :         enum win_type type = WIN_READ;
     288                 :        735 :         int prot = PROT_READ;
     289                 :            : 
     290                 :        735 :         assert(server_state.win_type == WIN_CLOSED);
     291                 :            : 
     292                 :            :         /* Shift params up */
     293                 :        735 :         offset <<= server_state.block_shift;
     294                 :        735 :         size <<= server_state.block_shift;
     295                 :            : 
     296                 :        735 :         if (!size || server_state.api == 1)
     297                 :        734 :                 size = server_state.def_read_win << server_state.block_shift;
     298                 :            : 
     299                 :        735 :         if (write) {
     300                 :         95 :                 max_size = server_state.max_write_win << server_state.block_shift;
     301                 :            :                 //win_size = server_state.def_write_win;
     302                 :         95 :                 prot |= PROT_WRITE;
     303                 :         95 :                 type = WIN_WRITE;
     304                 :            :                 /* Use the default size if zero size is set */
     305                 :         95 :                 if (!size || server_state.api == 1)
     306                 :         23 :                         size = server_state.def_write_win << server_state.block_shift;
     307                 :            :         }
     308                 :            : 
     309                 :            : 
     310                 :        735 :         prlog(PR_INFO, "Opening range %#.8x, %#.8x for %s\n",
     311                 :            :                         offset, offset + size - 1, write ? "writing" : "reading");
     312                 :            : 
     313                 :            :         /* XXX: Document this behaviour */
     314                 :        735 :         if ((size + offset) > server_state.lpc_size) {
     315                 :          4 :                 prlog(PR_INFO, "tried to open beyond end of flash\n");
     316                 :          4 :                 return MBOX_R_PARAM_ERROR;
     317                 :            :         }
     318                 :            : 
     319                 :            :         /* XXX: should we do this before or after checking for errors?
     320                 :            :          *      Doing it afterwards ensures consistency between
     321                 :            :          *      implementations
     322                 :            :          */
     323                 :        731 :         if (server_state.api == 2)
     324                 :        365 :                 size = MIN(size, max_size);
     325                 :            : 
     326                 :        731 :         mprotect(server_state.lpc_base + offset, size, prot);
     327                 :        731 :         server_state.win_type = type;
     328                 :        731 :         server_state.win_base = offset;
     329                 :        731 :         server_state.win_size = size;
     330                 :            : 
     331                 :        731 :         memset(msg->args, 0, sizeof(msg->args));
     332                 :        731 :         bmc_put_u16(msg, 0, offset >> server_state.block_shift);
     333                 :        731 :         if (server_state.api == 1) {
     334                 :            :                 /*
     335                 :            :                  * Put nonsense in here because v1 mbox-flash shouldn't know about it.
     336                 :            :                  * If v1 mbox-flash does read this, 0xffff should trigger a big mistake.
     337                 :            :                  */
     338                 :        187 :                 bmc_put_u16(msg, 2, 0xffff >> server_state.block_shift);
     339                 :        187 :                 bmc_put_u16(msg, 4, 0xffff >> server_state.block_shift);
     340                 :            :         } else {
     341                 :        544 :                 bmc_put_u16(msg, 2, size >> server_state.block_shift);
     342                 :        544 :                 bmc_put_u16(msg, 4, offset >> server_state.block_shift);
     343                 :            :         }
     344                 :        731 :         return MBOX_R_SUCCESS;
     345                 :            : }
     346                 :            : 
     347                 :        944 : int bmc_mbox_enqueue(struct bmc_mbox_msg *msg,
     348                 :            :                 unsigned int __unused timeout_sec)
     349                 :            : {
     350                 :            :         /*
     351                 :            :          * FIXME: should we be using the same storage for message
     352                 :            :          *        and response?
     353                 :            :          */
     354                 :        944 :         int rc = MBOX_R_SUCCESS;
     355                 :            :         uint32_t start, size;
     356                 :            : 
     357                 :        944 :         if (server_state.reset && msg->command != MBOX_C_GET_MBOX_INFO &&
     358                 :          3 :                                 msg->command != MBOX_C_BMC_EVENT_ACK) {
     359                 :            :                 /*
     360                 :            :                  * Real daemons should return an error, but for testing we'll
     361                 :            :                  * be a bit more strict
     362                 :            :                  */
     363                 :          0 :                 prlog(PR_EMERG, "Server was in reset state - illegal command %d\n",
     364                 :            :                         msg->command);
     365                 :          0 :                 exit(1);
     366                 :            :         }
     367                 :            : 
     368                 :        944 :         switch (msg->command) {
     369                 :          1 :                 case MBOX_C_RESET_STATE:
     370                 :          1 :                         prlog(PR_INFO, "RESET_STATE\n");
     371                 :          1 :                         server_state.win_type = WIN_CLOSED;
     372                 :          1 :                         rc = open_window(msg, false, 0, LPC_BLOCKS);
     373                 :          1 :                         memset(msg->args, 0, sizeof(msg->args));
     374                 :          1 :                         break;
     375                 :            : 
     376                 :          4 :                 case MBOX_C_GET_MBOX_INFO:
     377                 :          4 :                         prlog(PR_INFO, "GET_MBOX_INFO version = %d, block_shift = %d\n",
     378                 :            :                                         server_state.api, server_state.block_shift);
     379                 :          4 :                         msg->args[0] = server_state.api;
     380                 :          4 :                         if (server_state.api == 1) {
     381                 :          1 :                                 prlog(PR_INFO, "\tread_size = 0x%08x, write_size = 0x%08x\n",
     382                 :            :                                                 server_state.def_read_win, server_state.def_write_win);
     383                 :          1 :                                 bmc_put_u16(msg, 1, server_state.def_read_win);
     384                 :          1 :                                 bmc_put_u16(msg, 3, server_state.def_write_win);
     385                 :          1 :                                 msg->args[5] = 0xff; /* If v1 reads this, 0xff will force the mistake */
     386                 :            :                         } else {
     387                 :          3 :                                 msg->args[5] = server_state.block_shift;
     388                 :            :                         }
     389                 :          4 :                         server_state.reset = false;
     390                 :          4 :                         break;
     391                 :            : 
     392                 :          4 :                 case MBOX_C_GET_FLASH_INFO:
     393                 :          4 :                         prlog(PR_INFO, "GET_FLASH_INFO: size: 0x%" PRIu64 ", erase: 0x%08x\n",
     394                 :            :                                         server_state.lpc_size, server_state.erase_granule);
     395                 :          4 :                         if (server_state.api == 1) {
     396                 :          1 :                                 bmc_put_u32(msg, 0, server_state.lpc_size);
     397                 :          1 :                                 bmc_put_u32(msg, 4, server_state.erase_granule);
     398                 :            :                         } else {
     399                 :          3 :                                 bmc_put_u16(msg, 0, server_state.lpc_size >> server_state.block_shift);
     400                 :          3 :                                 bmc_put_u16(msg, 2, server_state.erase_granule >> server_state.block_shift);
     401                 :            :                         }
     402                 :          4 :                         break;
     403                 :            : 
     404                 :        639 :                 case MBOX_C_CREATE_READ_WINDOW:
     405                 :        639 :                         start = bmc_get_u16(msg, 0);
     406                 :        639 :                         size = bmc_get_u16(msg, 2);
     407                 :        639 :                         prlog(PR_INFO, "CREATE_READ_WINDOW: pos: 0x%08x, len: 0x%08x\n", start, size);
     408                 :        639 :                         rc = close_window(false);
     409                 :        639 :                         if (rc != MBOX_R_SUCCESS)
     410                 :          0 :                                 break;
     411                 :        639 :                         rc = open_window(msg, false, start, size);
     412                 :        639 :                         break;
     413                 :            : 
     414                 :          0 :                 case MBOX_C_CLOSE_WINDOW:
     415                 :          0 :                         rc = close_window(true);
     416                 :          0 :                         break;
     417                 :            : 
     418                 :         95 :                 case MBOX_C_CREATE_WRITE_WINDOW:
     419                 :         95 :                         start = bmc_get_u16(msg, 0);
     420                 :         95 :                         size = bmc_get_u16(msg, 2);
     421                 :         95 :                         prlog(PR_INFO, "CREATE_WRITE_WINDOW: pos: 0x%08x, len: 0x%08x\n", start, size);
     422                 :         95 :                         rc = close_window(false);
     423                 :         95 :                         if (rc != MBOX_R_SUCCESS)
     424                 :          0 :                                 break;
     425                 :         95 :                         rc = open_window(msg, true, start, size);
     426                 :         95 :                         break;
     427                 :            : 
     428                 :            :                 /* TODO: make these do something */
     429                 :         99 :                 case MBOX_C_WRITE_FLUSH:
     430                 :         99 :                         prlog(PR_INFO, "WRITE_FLUSH\n");
     431                 :            :                         /*
     432                 :            :                          * This behaviour isn't strictly illegal however it could
     433                 :            :                          * be a sign of bad behaviour
     434                 :            :                          */
     435                 :         99 :                         if (server_state.api > 1 && !server_state.win_dirty) {
     436                 :          0 :                                 prlog(PR_EMERG, "Version >1 called FLUSH without a previous DIRTY\n");
     437                 :          0 :                                 exit (1);
     438                 :            :                         }
     439                 :         99 :                         server_state.win_dirty = false;
     440                 :         99 :                         if (server_state.api > 1)
     441                 :         75 :                                 break;
     442                 :            : 
     443                 :            :                         /* This is only done on V1 */
     444                 :         24 :                         start = bmc_get_u16(msg, 0);
     445                 :         24 :                         if (server_state.api == 1)
     446                 :         24 :                                 size = bmc_get_u32(msg, 2);
     447                 :            :                         else
     448                 :          0 :                                 size = bmc_get_u16(msg, 2);
     449                 :         24 :                         prlog(PR_INFO, "\tpos: 0x%08x len: 0x%08x\n", start, size);
     450                 :         24 :                         rc = do_dirty(start, size);
     451                 :         24 :                         break;
     452                 :         96 :                 case MBOX_C_MARK_WRITE_DIRTY:
     453                 :         96 :                         start = bmc_get_u16(msg, 0);
     454                 :         96 :                         if (server_state.api == 1)
     455                 :         24 :                                 size = bmc_get_u32(msg, 2);
     456                 :            :                         else
     457                 :         72 :                                 size = bmc_get_u16(msg, 2);
     458                 :         96 :                         prlog(PR_INFO, "MARK_WRITE_DIRTY: pos: 0x%08x, len: %08x\n", start, size);
     459                 :         96 :                         server_state.win_dirty = true;
     460                 :         96 :                         rc = do_dirty(start, size);
     461                 :         96 :                         break;
     462                 :          3 :                 case MBOX_C_BMC_EVENT_ACK:
     463                 :            :                         /*
     464                 :            :                          * Clear any BMC notifier flags. Don't clear the server
     465                 :            :                          * reset state here, it is a permitted command but only
     466                 :            :                          * GET_INFO should clear it.
     467                 :            :                          *
     468                 :            :                          * Make sure that msg->args[0] is only acking bits we told
     469                 :            :                          * it about, in server_state.attn_reg. The caveat is that
     470                 :            :                          * it could NOT ack some bits...
     471                 :            :                          */
     472                 :          3 :                         prlog(PR_INFO, "BMC_EVENT_ACK 0x%02x\n", msg->args[0]);
     473                 :          3 :                         if ((msg->args[0] | server_state.attn_reg) != server_state.attn_reg) {
     474                 :          0 :                                 prlog(PR_EMERG, "Tried to ack bits we didn't say!\n");
     475                 :          0 :                                 exit(1);
     476                 :            :                         }
     477                 :          3 :                         msg->bmc &= ~msg->args[0];
     478                 :          3 :                         server_state.attn_reg &= ~msg->args[0];
     479                 :          3 :                         break;
     480                 :          3 :                 case MBOX_C_MARK_WRITE_ERASED:
     481                 :          3 :                         start = bmc_get_u16(msg, 0) << server_state.block_shift;
     482                 :          3 :                         size = bmc_get_u16(msg, 2) << server_state.block_shift;
     483                 :            :                         /* If we've negotiated v1 this should never be called */
     484                 :          3 :                         if (server_state.api == 1) {
     485                 :          0 :                                 prlog(PR_EMERG, "Version 1 protocol called a V2 only command\n");
     486                 :          0 :                                 exit(1);
     487                 :            :                         }
     488                 :            :                         /*
     489                 :            :                          * This will likely result in flush (but not
     490                 :            :                          * dirty) being called. This is the point.
     491                 :            :                          */
     492                 :          3 :                         server_state.win_dirty = true;
     493                 :            :                         /* This should really be done when they call flush */
     494                 :          3 :                         memset(server_state.lpc_base + server_state.win_base + start, 0xff, size);
     495                 :          3 :                         break;
     496                 :          0 :                 default:
     497                 :          0 :                         prlog(PR_EMERG, "Got unknown command code from mbox: %d\n", msg->command);
     498                 :            :         }
     499                 :            : 
     500                 :        944 :         prerror("command response = %d\n", rc);
     501                 :        944 :         msg->response = rc;
     502                 :            : 
     503                 :        944 :         mbox_data.msg = msg;
     504                 :            : 
     505                 :        944 :         return 0;
     506                 :            : }
     507                 :            : 
     508                 :         23 : int mbox_server_memcmp(int off, const void *buf, size_t len)
     509                 :            : {
     510                 :         23 :         return memcmp(server_state.lpc_base + off, buf, len);
     511                 :            : }
     512                 :            : 
     513                 :          4 : void mbox_server_memset(int c)
     514                 :            : {
     515                 :          4 :         memset(server_state.lpc_base, c, server_state.lpc_size);
     516                 :          4 : }
     517                 :            : 
     518                 :          4 : uint32_t mbox_server_total_size(void)
     519                 :            : {
     520                 :            :         /* Not actually but for this server we don't differentiate */
     521                 :          4 :         return server_state.lpc_size;
     522                 :            : }
     523                 :            : 
     524                 :          4 : uint32_t mbox_server_erase_granule(void)
     525                 :            : {
     526                 :          4 :         return server_state.erase_granule;
     527                 :            : }
     528                 :            : 
     529                 :          8 : int mbox_server_version(void)
     530                 :            : {
     531                 :          8 :         return server_state.api;
     532                 :            : }
     533                 :            : 
     534                 :          3 : int mbox_server_reset(unsigned int version, uint8_t block_shift)
     535                 :            : {
     536                 :          3 :         if (version > 3)
     537                 :          0 :                 return 1;
     538                 :            : 
     539                 :          3 :         server_state.api = version;
     540                 :          3 :         if (block_shift)
     541                 :          3 :                 server_state.block_shift = block_shift;
     542                 :          3 :         if (server_state.erase_granule < (1 << server_state.block_shift))
     543                 :          2 :                 server_state.erase_granule = 1 << server_state.block_shift;
     544                 :          3 :         server_state.lpc_size = LPC_BLOCKS * (1 << server_state.block_shift);
     545                 :          3 :         free(server_state.lpc_base);
     546                 :          3 :         server_state.lpc_base = malloc(server_state.lpc_size);
     547                 :          3 :         server_state.attn_reg = MBOX_ATTN_BMC_REBOOT | MBOX_ATTN_BMC_DAEMON_READY;
     548                 :          3 :         server_state.win_type = WIN_CLOSED;
     549                 :          3 :         server_state.reset = true;
     550                 :          3 :         mbox_data.attn(MBOX_ATTN_BMC_REBOOT, mbox_data.cb_attn);
     551                 :            : 
     552                 :          3 :         return 0;
     553                 :            : }
     554                 :            : 
     555                 :          1 : int mbox_server_init(void)
     556                 :            : {
     557                 :          1 :         server_state.api = 1;
     558                 :          1 :         server_state.reset = true;
     559                 :            : 
     560                 :            :         /* We're always ready! */
     561                 :          1 :         server_state.attn_reg = MBOX_ATTN_BMC_DAEMON_READY;
     562                 :            : 
     563                 :            :         /* setup server */
     564                 :          1 :         server_state.block_shift = 12;
     565                 :          1 :         server_state.erase_granule = 0x1000;
     566                 :          1 :         server_state.lpc_size = LPC_BLOCKS * (1 << server_state.block_shift);
     567                 :          1 :         server_state.lpc_base = malloc(server_state.lpc_size);
     568                 :            : 
     569                 :          1 :         server_state.def_read_win = 1; /* These are in units of block shift "= 1 is 4K" */
     570                 :          1 :         server_state.def_write_win = 1; /* These are in units of block shift "= 1 is 4K" */
     571                 :            : 
     572                 :          1 :         server_state.max_read_win = LPC_BLOCKS;
     573                 :          1 :         server_state.max_write_win = LPC_BLOCKS;
     574                 :          1 :         server_state.win_type = WIN_CLOSED;
     575                 :            : 
     576                 :          1 :         return 0;
     577                 :            : }
     578                 :            : 
     579                 :          1 : void mbox_server_destroy(void)
     580                 :            : {
     581                 :          1 :         free(server_state.lpc_base);
     582                 :          1 : }

Generated by: LCOV version 1.14