| Deepak Kodihalli | 6c2fa90 | 2017-05-01 06:36:02 -0500 | [diff] [blame] | 1 | /* | 
 | 2 |  * Mailbox Daemon Window Helpers | 
 | 3 |  * | 
 | 4 |  * Copyright 2017 IBM | 
 | 5 |  * | 
 | 6 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 | 7 |  * you may not use this file except in compliance with the License. | 
 | 8 |  * You may obtain a copy of the License at | 
 | 9 |  * | 
 | 10 |  * http://www.apache.org/licenses/LICENSE-2.0 | 
 | 11 |  * | 
 | 12 |  * Unless required by applicable law or agreed to in writing, software | 
 | 13 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 | 14 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | 15 |  * See the License for the specific language governing permissions and | 
 | 16 |  * limitations under the License. | 
 | 17 |  * | 
 | 18 |  */ | 
 | 19 |  | 
| Ratan Gupta | 8441a39 | 2017-05-05 21:42:53 +0530 | [diff] [blame] | 20 | #include <fcntl.h> | 
| Deepak Kodihalli | 6c2fa90 | 2017-05-01 06:36:02 -0500 | [diff] [blame] | 21 | #include <stdint.h> | 
 | 22 | #include <stdlib.h> | 
 | 23 | #include <syslog.h> | 
| Ratan Gupta | 8441a39 | 2017-05-05 21:42:53 +0530 | [diff] [blame] | 24 | #include <sys/mman.h> | 
 | 25 | #include <unistd.h> | 
| Deepak Kodihalli | abd52a7 | 2017-07-13 12:04:06 -0500 | [diff] [blame] | 26 | #include <sys/ioctl.h> | 
| Deepak Kodihalli | 7ee307c | 2017-07-12 03:41:08 -0500 | [diff] [blame] | 27 | #include <algorithm> | 
| Deepak Kodihalli | 6c2fa90 | 2017-05-01 06:36:02 -0500 | [diff] [blame] | 28 |  | 
 | 29 | extern "C" { | 
 | 30 | #include "common.h" | 
 | 31 | } | 
 | 32 |  | 
| Ratan Gupta | 8441a39 | 2017-05-05 21:42:53 +0530 | [diff] [blame] | 33 | #include "config.h" | 
| Deepak Kodihalli | 6c2fa90 | 2017-05-01 06:36:02 -0500 | [diff] [blame] | 34 | #include "mboxd_flash.h" | 
 | 35 | #include "mboxd_pnor_partition_table.h" | 
| Ratan Gupta | 6a98e18 | 2017-06-06 15:04:23 +0530 | [diff] [blame] | 36 | #include "pnor_partition.hpp" | 
 | 37 | #include "xyz/openbmc_project/Common/error.hpp" | 
 | 38 | #include <phosphor-logging/log.hpp> | 
 | 39 | #include <phosphor-logging/elog-errors.hpp> | 
| Deepak Kodihalli | 6c2fa90 | 2017-05-01 06:36:02 -0500 | [diff] [blame] | 40 |  | 
| Deepak Kodihalli | abd52a7 | 2017-07-13 12:04:06 -0500 | [diff] [blame] | 41 | #include <memory> | 
| Ratan Gupta | 8441a39 | 2017-05-05 21:42:53 +0530 | [diff] [blame] | 42 | #include <string> | 
 | 43 | #include <exception> | 
 | 44 | #include <stdexcept> | 
| Ratan Gupta | 8441a39 | 2017-05-05 21:42:53 +0530 | [diff] [blame] | 45 |  | 
| Deepak Kodihalli | abd52a7 | 2017-07-13 12:04:06 -0500 | [diff] [blame] | 46 | /** @brief unique_ptr functor to release a char* reference. */ | 
 | 47 | struct StringDeleter | 
 | 48 | { | 
 | 49 |     void operator()(char* ptr) const | 
 | 50 |     { | 
 | 51 |         free(ptr); | 
 | 52 |     } | 
 | 53 | }; | 
 | 54 | using StringPtr = std::unique_ptr<char, StringDeleter>; | 
 | 55 |  | 
 | 56 | int init_flash_dev(struct mbox_context *context) | 
 | 57 | { | 
 | 58 |     StringPtr filename(get_dev_mtd()); | 
 | 59 |     int fd = 0; | 
 | 60 |     int rc = 0; | 
 | 61 |  | 
 | 62 |     if (!filename) | 
 | 63 |     { | 
 | 64 |         MSG_ERR("Couldn't find the flash /dev/mtd partition\n"); | 
 | 65 |         return -1; | 
 | 66 |     } | 
 | 67 |  | 
 | 68 |     MSG_DBG("Opening %s\n", filename.get()); | 
 | 69 |  | 
 | 70 |     fd = open(filename.get(), O_RDWR); | 
 | 71 |     if (fd < 0) | 
 | 72 |     { | 
 | 73 |         MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n", | 
 | 74 |                 filename.get(), strerror(errno)); | 
 | 75 |         return -errno; | 
 | 76 |     } | 
 | 77 |  | 
 | 78 |     // Read the Flash Info | 
 | 79 |     if (ioctl(fd, MEMGETINFO, &context->mtd_info) == -1) | 
 | 80 |     { | 
 | 81 |         MSG_ERR("Couldn't get information about MTD: %s\n", | 
 | 82 |                 strerror(errno)); | 
 | 83 |         close(fd); | 
 | 84 |         return -errno; | 
 | 85 |     } | 
 | 86 |  | 
 | 87 |     if (context->flash_size == 0) | 
 | 88 |     { | 
 | 89 |         // See comment in mboxd_flash_physical.c on why | 
 | 90 |         // this is needed. | 
 | 91 |         context->flash_size = context->mtd_info.size; | 
 | 92 |     } | 
 | 93 |  | 
 | 94 |     // Hostboot requires a 4K block-size to be used in the FFS flash structure | 
 | 95 |     context->mtd_info.erasesize = 4096; | 
 | 96 |     context->erase_size_shift = log_2(context->mtd_info.erasesize); | 
 | 97 |     context->flash_bmap = NULL; | 
 | 98 |     context->fds[MTD_FD].fd = -1; | 
 | 99 |  | 
 | 100 |     close(fd); | 
 | 101 |     return rc; | 
 | 102 | } | 
 | 103 |  | 
 | 104 | void free_flash_dev(struct mbox_context *context) | 
 | 105 | { | 
 | 106 |     // No-op | 
 | 107 | } | 
 | 108 |  | 
 | 109 | int set_flash_bytemap(struct mbox_context *context, uint32_t offset, | 
 | 110 |                       uint32_t count, uint8_t val) | 
 | 111 | { | 
 | 112 |     // No-op | 
 | 113 |     return 0; | 
 | 114 | } | 
 | 115 |  | 
 | 116 | int erase_flash(struct mbox_context *context, uint32_t offset, uint32_t count) | 
 | 117 | { | 
 | 118 |     // No-op | 
 | 119 |     return 0; | 
 | 120 | } | 
 | 121 |  | 
| Deepak Kodihalli | 6c2fa90 | 2017-05-01 06:36:02 -0500 | [diff] [blame] | 122 | /* | 
 | 123 |  * copy_flash() - Copy data from the virtual pnor into a provided buffer | 
 | 124 |  * @context:    The mbox context pointer | 
 | 125 |  * @offset:     The pnor offset to copy from (bytes) | 
 | 126 |  * @mem:        The buffer to copy into (must be of atleast 'size' bytes) | 
 | 127 |  * @size:       The number of bytes to copy | 
| Deepak Kodihalli | 7ee307c | 2017-07-12 03:41:08 -0500 | [diff] [blame] | 128 |  * Return:      Number of bytes copied on success, otherwise negative error | 
 | 129 |  *              code. copy_flash will copy at most 'size' bytes, but it may | 
 | 130 |  *              copy less. | 
| Deepak Kodihalli | 6c2fa90 | 2017-05-01 06:36:02 -0500 | [diff] [blame] | 131 |  */ | 
| Deepak Kodihalli | 7ee307c | 2017-07-12 03:41:08 -0500 | [diff] [blame] | 132 | int64_t copy_flash(struct mbox_context* context, uint32_t offset, void* mem, | 
 | 133 |                    uint32_t size) | 
| Deepak Kodihalli | 6c2fa90 | 2017-05-01 06:36:02 -0500 | [diff] [blame] | 134 | { | 
| Ratan Gupta | 6a98e18 | 2017-06-06 15:04:23 +0530 | [diff] [blame] | 135 |     using namespace phosphor::logging; | 
 | 136 |     using namespace sdbusplus::xyz::openbmc_project::Common::Error; | 
 | 137 |     using namespace std::string_literals; | 
 | 138 |  | 
| Deepak Kodihalli | 7ee307c | 2017-07-12 03:41:08 -0500 | [diff] [blame] | 139 |     int rc = size; | 
| Deepak Kodihalli | 6c2fa90 | 2017-05-01 06:36:02 -0500 | [diff] [blame] | 140 |  | 
 | 141 |     MSG_DBG("Copy virtual pnor to %p for size 0x%.8x from offset 0x%.8x\n", | 
 | 142 |             mem, size, offset); | 
 | 143 |  | 
 | 144 |     /* The virtual PNOR partition table starts at offset 0 in the virtual | 
 | 145 |      * pnor image. Check if host asked for an offset that lies within the | 
 | 146 |      * partition table. | 
 | 147 |      */ | 
| Ratan Gupta | 8441a39 | 2017-05-05 21:42:53 +0530 | [diff] [blame] | 148 |     try | 
| Deepak Kodihalli | 6c2fa90 | 2017-05-01 06:36:02 -0500 | [diff] [blame] | 149 |     { | 
| Ratan Gupta | 8441a39 | 2017-05-05 21:42:53 +0530 | [diff] [blame] | 150 |         size_t sz = | 
 | 151 |             vpnor_get_partition_table_size(context) << context->block_size_shift; | 
 | 152 |         if (offset < sz) | 
 | 153 |         { | 
 | 154 |             const struct pnor_partition_table* table = | 
 | 155 |                 vpnor_get_partition_table(context); | 
| Deepak Kodihalli | 7ee307c | 2017-07-12 03:41:08 -0500 | [diff] [blame] | 156 |             rc = std::min(sz - offset, static_cast<size_t>(size)); | 
 | 157 |             memcpy(mem, ((uint8_t*)table) + offset, rc); | 
| Ratan Gupta | 8441a39 | 2017-05-05 21:42:53 +0530 | [diff] [blame] | 158 |         } | 
 | 159 |         else | 
 | 160 |         { | 
| Ratan Gupta | 6a98e18 | 2017-06-06 15:04:23 +0530 | [diff] [blame] | 161 |             openpower::virtual_pnor::RORequest roRequest; | 
 | 162 |             auto partitionInfo = roRequest.getPartitionInfo(context, offset); | 
| Deepak Kodihalli | 6c2fa90 | 2017-05-01 06:36:02 -0500 | [diff] [blame] | 163 |  | 
| Ratan Gupta | 6a98e18 | 2017-06-06 15:04:23 +0530 | [diff] [blame] | 164 |             auto mapped_mem = mmap(NULL, partitionInfo->data.actual, | 
 | 165 |                                    PROT_READ, MAP_PRIVATE, roRequest.fd(), 0); | 
| Ratan Gupta | 8441a39 | 2017-05-05 21:42:53 +0530 | [diff] [blame] | 166 |  | 
| Adriana Kobylak | 0a2cc95 | 2017-10-12 11:13:06 -0500 | [diff] [blame] | 167 |             if (mapped_mem == MAP_FAILED) | 
| Ratan Gupta | 8441a39 | 2017-05-05 21:42:53 +0530 | [diff] [blame] | 168 |             { | 
| Ratan Gupta | 6a98e18 | 2017-06-06 15:04:23 +0530 | [diff] [blame] | 169 |                 MSG_ERR("Failed to map partition=%s:Error=%s\n", | 
 | 170 |                         partitionInfo->data.name, strerror(errno)); | 
 | 171 |  | 
 | 172 |                 elog<InternalFailure>(); | 
 | 173 |             } | 
 | 174 |  | 
 | 175 |             // if the asked offset + no of bytes to read is greater | 
 | 176 |             // then size of the partition file then throw error. | 
 | 177 |  | 
 | 178 |             uint32_t baseOffset = partitionInfo->data.base << context->block_size_shift; | 
| Ratan Gupta | 8441a39 | 2017-05-05 21:42:53 +0530 | [diff] [blame] | 179 |             //copy to the reserved memory area | 
| Ratan Gupta | 6a98e18 | 2017-06-06 15:04:23 +0530 | [diff] [blame] | 180 |             auto diffOffset = offset - baseOffset; | 
| Deepak Kodihalli | b100fb8 | 2017-07-12 04:44:41 -0500 | [diff] [blame] | 181 |             rc = std::min(partitionInfo->data.actual - diffOffset, size); | 
 | 182 |             memcpy(mem, (char*)mapped_mem + diffOffset , rc); | 
| Ratan Gupta | 6a98e18 | 2017-06-06 15:04:23 +0530 | [diff] [blame] | 183 |             munmap(mapped_mem, partitionInfo->data.actual); | 
| Ratan Gupta | 8441a39 | 2017-05-05 21:42:53 +0530 | [diff] [blame] | 184 |         } | 
 | 185 |     } | 
| Ratan Gupta | 6a98e18 | 2017-06-06 15:04:23 +0530 | [diff] [blame] | 186 |     catch (InternalFailure& e) | 
| Ratan Gupta | 8441a39 | 2017-05-05 21:42:53 +0530 | [diff] [blame] | 187 |     { | 
| Ratan Gupta | 6a98e18 | 2017-06-06 15:04:23 +0530 | [diff] [blame] | 188 |         commit<InternalFailure>(); | 
| Deepak Kodihalli | f9abed0 | 2017-07-17 06:23:08 -0500 | [diff] [blame] | 189 |         rc = -MBOX_R_SYSTEM_ERROR; | 
| Ratan Gupta | 8441a39 | 2017-05-05 21:42:53 +0530 | [diff] [blame] | 190 |     } | 
| Deepak Kodihalli | 6c2fa90 | 2017-05-01 06:36:02 -0500 | [diff] [blame] | 191 |     return rc; | 
 | 192 | } | 
| Ratan Gupta | dc50ce5 | 2017-05-31 15:47:55 +0530 | [diff] [blame] | 193 |  | 
 | 194 | /* | 
 | 195 |  * write_flash() - Write to the virtual pnor from a provided buffer | 
 | 196 |  * @context: The mbox context pointer | 
 | 197 |  * @offset:  The flash offset to write to (bytes) | 
 | 198 |  * @buf:     The buffer to write from (must be of atleast size) | 
 | 199 |  * @size:    The number of bytes to write | 
 | 200 |  * | 
 | 201 |  * Return:  0 on success otherwise negative error code | 
 | 202 |  */ | 
 | 203 |  | 
 | 204 | int write_flash(struct mbox_context* context, uint32_t offset, void* buf, | 
 | 205 |                 uint32_t count) | 
 | 206 | { | 
 | 207 |     using namespace phosphor::logging; | 
 | 208 |     using namespace sdbusplus::xyz::openbmc_project::Common::Error; | 
 | 209 |     using namespace std::string_literals; | 
 | 210 |  | 
 | 211 |     int rc = 0; | 
 | 212 |     MSG_DBG("Write flash @ 0x%.8x for 0x%.8x from %p\n", offset, count, buf); | 
 | 213 |     try | 
 | 214 |     { | 
 | 215 |         openpower::virtual_pnor::RWRequest rwRequest; | 
 | 216 |         auto partitionInfo = rwRequest.getPartitionInfo(context, offset); | 
 | 217 |  | 
 | 218 |  | 
 | 219 |         auto mapped_mem = mmap(NULL, partitionInfo->data.actual, | 
 | 220 |                                PROT_READ | PROT_WRITE, | 
 | 221 |                                MAP_SHARED, rwRequest.fd(), 0); | 
 | 222 |         if (mapped_mem == MAP_FAILED) | 
 | 223 |         { | 
 | 224 |             MSG_ERR("Failed to map partition=%s:Error=%s\n", | 
 | 225 |                     partitionInfo->data.name, strerror(errno)); | 
 | 226 |  | 
 | 227 |             elog<InternalFailure>(); | 
 | 228 |         } | 
 | 229 |         //copy to the mapped memory. | 
 | 230 |  | 
 | 231 |         uint32_t baseOffset = partitionInfo->data.base << context->block_size_shift; | 
 | 232 |  | 
 | 233 |         // if the asked offset + no of bytes to write is greater | 
 | 234 |         // then size of the partition file then throw error. | 
 | 235 |         if ((offset + count) > (baseOffset + partitionInfo->data.actual)) | 
 | 236 |         { | 
 | 237 |             MSG_ERR("Offset is beyond the partition file length[0x%.8x]\n", | 
 | 238 |                      partitionInfo->data.actual); | 
 | 239 |             munmap(mapped_mem, partitionInfo->data.actual); | 
 | 240 |             elog<InternalFailure>(); | 
 | 241 |         } | 
 | 242 |  | 
 | 243 |         auto diffOffset = offset - baseOffset; | 
 | 244 |         memcpy((char*)mapped_mem + diffOffset , buf, count); | 
 | 245 |         munmap(mapped_mem, partitionInfo->data.actual); | 
 | 246 |  | 
 | 247 |         set_flash_bytemap(context, offset, count, FLASH_DIRTY); | 
 | 248 |     } | 
 | 249 |     catch (InternalFailure & e) | 
 | 250 |     { | 
 | 251 |         rc = -1; | 
 | 252 |     } | 
 | 253 |     return rc; | 
 | 254 | } |