blob: 39ddf772d940c27e4b6fe4bdc1158f7413d58656 [file] [log] [blame]
Brandon Kim55dcada2022-03-09 02:18:01 -08001#include "pci_handler.hpp"
2
3#include <fcntl.h>
Brandon Kim55dcada2022-03-09 02:18:01 -08004
5#include <stdplus/fd/managed.hpp>
6#include <stdplus/fd/mmap.hpp>
Patrick Williams5de90612024-02-13 21:31:53 -06007#include <stdplus/print.hpp>
Brandon Kim55dcada2022-03-09 02:18:01 -08008
9#include <cstdint>
10#include <cstring>
Patrick Williams5de90612024-02-13 21:31:53 -060011#include <format>
Brandon Kim55dcada2022-03-09 02:18:01 -080012#include <memory>
13#include <span>
14#include <vector>
15
16namespace bios_bmc_smm_error_logger
17{
18
19PciDataHandler::PciDataHandler(uint32_t regionAddress, size_t regionSize,
20 std::unique_ptr<stdplus::fd::Fd> fd) :
Patrick Williams1a643562024-08-16 15:22:05 -040021 regionSize(regionSize), fd(std::move(fd)),
Brandon Kim55dcada2022-03-09 02:18:01 -080022 mmap(stdplus::fd::MMap(
23 *this->fd, regionSize, stdplus::fd::ProtFlags{PROT_READ | PROT_WRITE},
24 stdplus::fd::MMapFlags{stdplus::fd::MMapAccess::Shared}, regionAddress))
25{}
26
27std::vector<uint8_t> PciDataHandler::read(const uint32_t offset,
28 const uint32_t length)
29{
30 if (offset > regionSize || length == 0)
31 {
Patrick Williams5de90612024-02-13 21:31:53 -060032 stdplus::print(stderr,
33 "[read] Offset [{}] was bigger than regionSize [{}] "
34 "OR length [{}] was equal to 0\n",
35 offset, regionSize, length);
Brandon Kim55dcada2022-03-09 02:18:01 -080036 return {};
37 }
38
39 // Read up to regionSize in case the offset + length overflowed
Patrick Williams1a643562024-08-16 15:22:05 -040040 uint32_t finalLength =
41 (offset + length < regionSize) ? length : regionSize - offset;
Brandon Kim55dcada2022-03-09 02:18:01 -080042 std::vector<uint8_t> results(finalLength);
43
Brandon Kim454b3042025-06-08 21:38:48 +000044 // Use a volatile pointer to ensure every access reads directly from the
45 // memory-mapped region, preventing compiler optimizations like caching.
46 const volatile uint8_t* src =
47 reinterpret_cast<volatile const uint8_t*>(mmap.get().data() + offset);
48
49 // Perform a byte-by-byte copy to avoid undefined behavior with memcpy on
50 // volatile memory.
51 for (uint32_t i = 0; i < finalLength; ++i)
52 {
53 results[i] = src[i];
54 }
Brandon Kim55dcada2022-03-09 02:18:01 -080055 return results;
56}
57
58uint32_t PciDataHandler::write(const uint32_t offset,
59 const std::span<const uint8_t> bytes)
60{
61 const size_t length = bytes.size();
62 if (offset > regionSize || length == 0)
63 {
Patrick Williams5de90612024-02-13 21:31:53 -060064 stdplus::print(stderr,
65 "[write] Offset [{}] was bigger than regionSize [{}] "
66 "OR length [{}] was equal to 0\n",
67 offset, regionSize, length);
Brandon Kim55dcada2022-03-09 02:18:01 -080068 return 0;
69 }
70
71 // Write up to regionSize in case the offset + length overflowed
Patrick Williams1a643562024-08-16 15:22:05 -040072 uint16_t finalLength =
73 (offset + length < regionSize) ? length : regionSize - offset;
Brandon Kim454b3042025-06-08 21:38:48 +000074 // Use a volatile pointer to ensure every access writes directly to the
75 // memory-mapped region.
76 volatile uint8_t* dest =
77 reinterpret_cast<volatile uint8_t*>(mmap.get().data() + offset);
78
79 // Perform a byte-by-byte copy to ensure volatile semantics.
80 for (uint16_t i = 0; i < finalLength; ++i)
81 {
82 dest[i] = bytes[i];
83 }
Brandon Kim55dcada2022-03-09 02:18:01 -080084 return finalLength;
85}
86
87uint32_t PciDataHandler::getMemoryRegionSize()
88{
89 return regionSize;
90}
91
92} // namespace bios_bmc_smm_error_logger