fsm/src/device/PCIEDevice.cpp
2021-10-24 21:32:49 +02:00

228 lines
6.2 KiB
C++

#include <cstring>
#include <dirent.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <fstream>
#include <sstream>
#include "PCIEDevice.h"
#include "fm10k/FM10K.h"
std::vector<uint8_t> get_file_contents(const std::string& path){
std::ifstream file;
file.open(path, std::ios::in | std::ios::binary);
if(file.fail()){
file.close();
return {};
}
std::vector<uint8_t> data;
std::for_each(std::istreambuf_iterator<char>(file),
std::istreambuf_iterator<char>(),
[&data](const char c){
data.push_back(c);
});
file.close();
return std::move(data);
}
uint64_t get_file_integer(const std::string& path){
auto s = get_file_contents(path);
std::string t;
t.reserve(s.empty() ? 0 : s.size() - 1);
for(auto& c : s){
if(c == '\n'){
break;
}
t += c;
}
if(t.empty()){
return -1;
}
return std::strtoul(t.c_str(), nullptr, 0);
}
std::vector<PCIEDevice::DeviceEntry> PCIEDevice::DeviceEntry::find() {
std::vector<PCIEDevice::DeviceEntry> entries;
//TODO: BSD?
DIR *folder;
folder = opendir("/sys/bus/pci/devices");
if (folder == nullptr) {
return entries;
}
struct dirent *entry;
while ((entry = readdir(folder))) {
std::string basePath("/sys/bus/pci/devices/");
basePath += entry->d_name;
if (entry->d_type == DT_DIR || entry->d_type == DT_LNK) {
uint16_t vendor = get_file_integer(basePath + "/vendor");
uint16_t _class = get_file_integer(basePath + "/device");
if (
vendor == 0x8086 //Intel Corporation
&&
(_class == 0x15a4 || _class == 0x15d0 || _class == 0x15d5) //FM10000 devices
) {
if (access((basePath + "/resource4").c_str(), F_OK) == 0) {
auto vpd = get_file_contents(basePath + "/vpd");
entries.emplace_back(basePath + "/resource4", vendor, _class, vpd);
}
}
}
}
closedir(folder);
return entries;
}
PCIEDevice::PCIEDevice(const PCIEDevice::DeviceEntry& device) : m_device (device){
m_bar4Resource = open(m_device.getPath().c_str(), O_RDWR);
if(m_bar4Resource <= 0){
//TODO printf("Unable to open BAR4 resource %s\n", m_device.getPath().c_str());
return;
}
m_bar4mmap = static_cast<uint32_t *>(mmap(nullptr, FM10K::BAR4_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, m_bar4Resource, 0));
if(m_bar4mmap == MAP_FAILED){
//TODO printf("Unable to map BAR4 resource %s\n", m_device.getPath().c_str());
close(m_bar4Resource);
m_bar4Resource = 0;
m_bar4mmap = nullptr;
return;
}
}
PCIEDevice::~PCIEDevice() {
if(m_bar4mmap != nullptr){
if(munmap(m_bar4mmap, FM10K::BAR4_SIZE) != 0){
//Error
}
m_bar4mmap = nullptr;
}
if(m_bar4Resource > 0){
close(m_bar4Resource);
m_bar4Resource = 0;
}
}
uint32_t PCIEDevice::get32(uint32_t address) const {
return (m_bar4mmap && address < FM10K::BAR4_SIZE) ? *getaddress(address) : 0;
}
void PCIEDevice::set32(uint32_t address, uint32_t value) const {
if(m_bar4mmap && address < FM10K::BAR4_SIZE){
*getaddress(address) = value;
}
}
uint64_t PCIEDevice::get64(uint32_t address) const {
return (m_bar4mmap && (address + 1) < FM10K::BAR4_SIZE) ? *reinterpret_cast<volatile uint64_t*>(getaddress(address)) : 0;
}
void PCIEDevice::set64(uint32_t address, uint64_t value) const {
if(m_bar4mmap && (address + 1) < FM10K::BAR4_SIZE){
*reinterpret_cast<volatile uint64_t*>(getaddress(address)) = value;
}
}
volatile uint32_t* PCIEDevice::map32(uint32_t address) const {
return (m_bar4mmap && address < FM10K::BAR4_SIZE) ? getaddress(address) : nullptr;
}
PCIEDevice::VitalProductData::VitalProductData(const std::vector<uint8_t>& s) {
size_t offset = 0;
while(offset < s.size()){
ResourceType t(s, offset);
switch (t.getName()) {
case ResourceType::TypeName::StringTag:
if(m_vpd.empty()){
//Product Name
m_vpd.emplace("Product Name", t.getData());
}
break;
case ResourceType::TypeName::VPD_R:
{
size_t o = 0;
while (o < t.getData().size()){
fillFromEntry(t.getData(), o);
}
}
break;
case ResourceType::TypeName::VPD_W:
{
size_t o = 0;
while (o < t.getData().size()){
fillFromEntry(t.getData(), o);
}
}
break;
case ResourceType::TypeName::End:
return;
}
};
}
void PCIEDevice::VitalProductData::fillFromEntry(const std::vector<uint8_t> &v, size_t& offset) {
std::string keyword;
keyword.reserve(2);
keyword += static_cast<char>(v[offset++]);
keyword += static_cast<char>(v[offset++]);
uint8_t length = v[offset++];
std::vector<uint8_t> data;
std::copy(v.begin() + offset, v.begin() + offset + length, std::back_inserter(data));
offset += length;
m_vpd.emplace(std::move(keyword), std::move(data));
}
PCIEDevice::VitalProductData::ResourceType::ResourceType(const std::vector<uint8_t>& s, size_t& offset) {
uint8_t h = s[offset++];
uint16_t length = 0;
if(((h>>7)&1) == 0){ //Small Data Type
PACKED(struct {
uint8_t length : 3;
uint8_t name : 4;
uint8_t type : 1;
}, uint8_t) header{};
header.value = h;
m_name = static_cast<TypeName>(header.fields.name);
length = header.fields.length;
}else{ //Large Data Type
PACKED(struct {
uint8_t name : 7;
uint8_t type : 1;
}, uint8_t) header{};
header.value = h;
m_name = static_cast<TypeName>(header.fields.name);
length = s[offset] | s[offset + 1] << 8;
offset += 2;
}
std::copy(s.begin() + offset, s.begin() + offset + length, std::back_inserter(m_data));
offset += length;
}