2 * Copyright (c) 2013-2019, Intel Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12 * * Neither the name of Intel Corporation nor the names of its contributors
13 * may be used to endorse or promote products derived from this software
14 * without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
29 #include "pt_section.h"
30 #include "pt_section_posix.h"
31 #include "pt_section_file.h"
39 #include <sys/types.h>
45 int pt_section_mk_status(void **pstatus, uint64_t *psize, const char *filename)
47 struct pt_sec_posix_status *status;
51 if (!pstatus || !psize)
54 errcode = stat(filename, &buffer);
58 if (buffer.st_size < 0)
59 return -pte_bad_image;
61 status = malloc(sizeof(*status));
65 status->stat = buffer;
68 *psize = (uint64_t) buffer.st_size;
73 static int check_file_status(struct pt_section *section, int fd)
75 struct pt_sec_posix_status *status;
82 errcode = fstat(fd, &stat);
86 status = section->status;
90 if (stat.st_size != status->stat.st_size)
91 return -pte_bad_image;
93 if (stat.st_mtime != status->stat.st_mtime)
94 return -pte_bad_image;
99 int pt_sec_posix_map(struct pt_section *section, int fd)
101 struct pt_sec_posix_mapping *mapping;
102 uint64_t offset, size, adjustment;
108 return -pte_internal;
110 offset = section->offset;
111 size = section->size;
113 page_size = sysconf(_SC_PAGESIZE);
115 return -pte_bad_config;
117 adjustment = offset % (uint64_t) page_size;
119 offset -= adjustment;
122 /* The section is supposed to fit into the file so we shouldn't
123 * see any overflows, here.
125 if (size < section->size)
126 return -pte_internal;
131 if (INT_MAX < offset)
134 base = mmap(NULL, (size_t) size, PROT_READ, MAP_SHARED, fd,
136 if (base == MAP_FAILED)
139 mapping = malloc(sizeof(*mapping));
141 errcode = -pte_nomem;
145 mapping->base = base;
146 mapping->size = size;
147 mapping->begin = base + adjustment;
148 mapping->end = base + size;
150 section->mapping = mapping;
151 section->unmap = pt_sec_posix_unmap;
152 section->read = pt_sec_posix_read;
153 section->memsize = pt_sec_posix_memsize;
158 munmap(base, (size_t) size);
162 static int pt_sec_posix_map_success(struct pt_section *section)
168 return -pte_internal;
170 mcount = section->mcount + 1;
172 (void) pt_section_unlock(section);
173 return -pte_overflow;
176 section->mcount = mcount;
178 errcode = pt_section_unlock(section);
182 status = pt_section_on_map(section);
184 /* We had to release the section lock for pt_section_on_map() so
185 * @section may have meanwhile been mapped by other threads.
187 * We still want to return the error so we release our mapping.
188 * Our caller does not yet know whether pt_section_map()
191 (void) pt_section_unmap(section);
198 int pt_section_map(struct pt_section *section)
200 const char *filename;
205 return -pte_internal;
207 errcode = pt_section_lock(section);
212 return pt_sec_posix_map_success(section);
214 if (section->mapping)
217 filename = section->filename;
221 errcode = -pte_bad_file;
222 fd = open(filename, O_RDONLY);
226 errcode = check_file_status(section, fd);
230 /* We close the file on success. This does not unmap the section. */
231 errcode = pt_sec_posix_map(section, fd);
235 return pt_sec_posix_map_success(section);
238 /* Fall back to file based sections - report the original error
239 * if we fail to convert the file descriptor.
241 file = fdopen(fd, "rb");
243 errcode = -pte_bad_file;
247 /* We need to keep the file open on success. It will be closed when
248 * the section is unmapped.
250 errcode = pt_sec_file_map(section, file);
252 return pt_sec_posix_map_success(section);
261 (void) pt_section_unlock(section);
265 int pt_sec_posix_unmap(struct pt_section *section)
267 struct pt_sec_posix_mapping *mapping;
270 return -pte_internal;
272 mapping = section->mapping;
273 if (!mapping || !section->unmap || !section->read || !section->memsize)
274 return -pte_internal;
276 section->mapping = NULL;
277 section->unmap = NULL;
278 section->read = NULL;
279 section->memsize = NULL;
281 munmap(mapping->base, (size_t) mapping->size);
287 int pt_sec_posix_read(const struct pt_section *section, uint8_t *buffer,
288 uint16_t size, uint64_t offset)
290 struct pt_sec_posix_mapping *mapping;
291 const uint8_t *begin;
293 if (!buffer || !section)
294 return -pte_internal;
296 mapping = section->mapping;
298 return -pte_internal;
300 /* We already checked in pt_section_read() that the requested memory
301 * lies within the section's boundaries.
303 * And we checked that the entire section was mapped. There's no need
304 * to check for overflows, again.
306 begin = mapping->begin + offset;
308 memcpy(buffer, begin, size);
312 int pt_sec_posix_memsize(const struct pt_section *section, uint64_t *size)
314 struct pt_sec_posix_mapping *mapping;
315 const uint8_t *begin, *end;
317 if (!section || !size)
318 return -pte_internal;
320 mapping = section->mapping;
322 return -pte_internal;
324 begin = mapping->base;
327 if (!begin || !end || end < begin)
328 return -pte_internal;
330 *size = (uint64_t) (end - begin);