coreboot_table/
lib.rs

1#![no_std]
2
3use core::{mem, ptr};
4
5pub use self::cb64::Cb64;
6pub use self::cmos::{Cmos, CmosEntry, CmosEnum, CmosRecord};
7pub use self::forward::Forward;
8pub use self::framebuffer::Framebuffer;
9pub use self::header::Header;
10pub use self::mapper::{Mapper, PhysicalAddress, VirtualAddress};
11pub use self::memory::{Memory, MemoryRange, MemoryRangeKind};
12pub use self::record::{Record, RecordKind};
13pub use self::serial::Serial;
14
15mod cb64;
16mod cmos;
17mod forward;
18mod framebuffer;
19mod header;
20mod mapper;
21mod memory;
22mod record;
23mod serial;
24
25#[derive(Debug)]
26pub enum Table<'a> {
27    Cmos(&'a Cmos),
28    Framebuffer(&'a Framebuffer),
29    Memory(&'a Memory),
30    Serial(&'a Serial),
31    Other(&'a Record),
32}
33
34pub fn tables<F: FnMut(Table) -> Result<(), &'static str>, M: Mapper>(callback: F, mapper: &mut M) -> Result<(), &'static str> {
35    let mut env = Env {
36        callback,
37        mapper
38    };
39    env.tables()
40}
41
42struct Env<'m, F: FnMut(Table) -> Result<(), &'static str>, M: Mapper>  {
43    callback: F,
44    mapper: &'m mut M,
45}
46
47impl<'m, F: FnMut(Table) -> Result<(), &'static str>, M: Mapper> Env<'m, F, M> {
48    fn forward(&mut self, forward: &Forward) -> Result<(), &'static str> {
49        let page_size = self.mapper.page_size();
50
51        let header_physical = PhysicalAddress(forward.forward as usize);
52        let header_address = unsafe { self.mapper.map(header_physical, page_size)? };
53
54        let header = unsafe { ptr::read((header_address.0) as *const Header) };
55
56        unsafe { self.mapper.unmap(header_address)? };
57
58        if header.is_valid() {
59            self.header(header, PhysicalAddress(header_physical.0))
60        } else {
61            Err("Forward header invalid")
62        }
63    }
64
65    fn header(&mut self, header: Header, header_physical: PhysicalAddress) -> Result<(), &'static str> {
66        let mut result = Ok(());
67
68        let table_physical = PhysicalAddress(header_physical.0 + header.header_bytes as usize);
69        let table_size = header.table_bytes as usize;
70        let table_address = unsafe { self.mapper.map(table_physical, table_size)? };
71        let table_entries = header.table_entries as usize;
72        {
73            let mut i = 0;
74            let mut entries = 0;
75            while i + mem::size_of::<Record>() <= table_size && entries < table_entries {
76                let record_address = table_address.0 + i;
77                let record = unsafe { &*(record_address as *const Record) };
78
79                result = match record.kind {
80                    RecordKind::CmosOptionTable => {
81                        (self.callback)(Table::Cmos(
82                            unsafe { &*(record_address as *const Cmos) }
83                        ))
84                    },
85                    RecordKind::Forward => {
86                        let forward = unsafe { &*(record_address as *const Forward) };
87                        self.forward(forward)
88                    },
89                    RecordKind::Framebuffer => (self.callback)(Table::Framebuffer(
90                        unsafe { &*(record_address as *const Framebuffer) }
91                    )),
92                    RecordKind::Memory => (self.callback)(Table::Memory(
93                        unsafe { &*(record_address as *const Memory) }
94                    )),
95                    RecordKind::Serial => (self.callback)(Table::Serial (
96                        unsafe { &*(record_address as *const Serial) }
97                    )),
98                    _ => (self.callback)(Table::Other(record)),
99                };
100
101                if ! result.is_ok() {
102                    break;
103                }
104
105                i += record.size as usize;
106                entries += 1;
107            }
108        }
109
110        unsafe { self.mapper.unmap(table_address)? };
111
112        return result;
113    }
114
115    pub fn tables(&mut self) -> Result<(), &'static str> {
116        let page_size = self.mapper.page_size();
117
118        // First, we need to find the header somewhere in low memory
119        let low_memory = 1024 * 1024;
120        for header_page in 0..(low_memory / page_size) {
121            let header_physical = PhysicalAddress(header_page * page_size);
122            let header_address = unsafe { self.mapper.map(header_physical, page_size)? };
123
124            {
125                let mut i = 0;
126                while i + mem::size_of::<Header>() <= page_size {
127                    let header = unsafe { ptr::read((header_address.0 + i) as *const Header) };
128
129                    if header.is_valid() {
130                        unsafe { self.mapper.unmap(header_address)? };
131
132                        return self.header(header, PhysicalAddress(header_physical.0 + i));
133                    }
134
135                    i += 4;
136                }
137            }
138
139            unsafe { self.mapper.unmap(header_address)? };
140        }
141
142        // Header not found
143        Err("Header not found")
144    }
145}