1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// SPDX-License-Identifier: MIT

use intel_spi::{Mapper, SpiDev, PhysicalAddress, VirtualAddress};

use std::{fs, ptr};

pub struct LinuxMapper;

impl Mapper for LinuxMapper {
    unsafe fn map_aligned(&mut self, address: PhysicalAddress, size: usize) -> Result<VirtualAddress, &'static str> {
        let fd = libc::open(
            b"/dev/mem\0".as_ptr() as *const libc::c_char,
            libc::O_RDWR
        );
        if fd < 0 {
            return Err("failed to open /dev/mem")
        }

        let ptr = libc::mmap(
            ptr::null_mut(),
            size,
            libc::PROT_READ | libc::PROT_WRITE,
            libc::MAP_SHARED,
            fd,
            address.0 as libc::off_t
        );

        libc::close(fd);

        if ptr == libc::MAP_FAILED {
            return Err("failed to map /dev/mem");
        }

        Ok(VirtualAddress(ptr as usize))
    }

    unsafe fn unmap_aligned(&mut self, address: VirtualAddress, size: usize) -> Result<(), &'static str> {
        if libc::munmap(address.0 as *mut libc::c_void, size) == 0 {
            Ok(())
        } else {
            Err("failed to unmap /dev/mem")
        }
    }

    fn page_size(&self) -> usize {
        //TODO: get dynamically
        4096
    }
}

pub unsafe fn get_spi() -> SpiDev<'static, LinuxMapper> {
    static mut LINUX_MAPPER: LinuxMapper = LinuxMapper;
    let mcfg = fs::read("/sys/firmware/acpi/tables/MCFG").expect("failed to read MCFG");
    SpiDev::new(&mcfg, &mut LINUX_MAPPER).expect("failed to get SPI device")
}