const DRAM_BASE: u64 = 0x80000000;
const DTB_SIZE: usize = 0xfe0;
use memory::Memory;
use cpu::{PrivilegeMode, Trap, TrapType, Xlen};
use device::virtio_block_disk::VirtioBlockDisk;
use device::plic::Plic;
use device::clint::Clint;
use device::uart::Uart;
use terminal::Terminal;
pub struct Mmu {
clock: u64,
xlen: Xlen,
ppn: u64,
addressing_mode: AddressingMode,
privilege_mode: PrivilegeMode,
memory: MemoryWrapper,
dtb: Vec<u8>,
disk: VirtioBlockDisk,
plic: Plic,
clint: Clint,
uart: Uart
}
pub enum AddressingMode {
None,
SV32,
SV39,
SV48
}
enum MemoryAccessType {
Execute,
Read,
Write,
DontCare
}
fn _get_addressing_mode_name(mode: &AddressingMode) -> &'static str {
match mode {
AddressingMode::None => "None",
AddressingMode::SV32 => "SV32",
AddressingMode::SV39 => "SV39",
AddressingMode::SV48 => "SV48"
}
}
impl Mmu {
pub fn new(xlen: Xlen, terminal: Box<dyn Terminal>) -> Self {
let mut dtb = vec![0; DTB_SIZE];
load_default_dtb_content(&mut dtb);
Mmu {
clock: 0,
xlen: xlen,
ppn: 0,
addressing_mode: AddressingMode::None,
privilege_mode: PrivilegeMode::Machine,
memory: MemoryWrapper::new(),
dtb: dtb,
disk: VirtioBlockDisk::new(),
plic: Plic::new(),
clint: Clint::new(),
uart: Uart::new(terminal)
}
}
pub fn update_xlen(&mut self, xlen: Xlen) {
self.xlen = xlen;
}
pub fn init_memory(&mut self, capacity: u64) {
self.memory.init(capacity);
}
pub fn init_disk(&mut self, data: Vec<u8>) {
self.disk.init(data);
}
pub fn init_dtb(&mut self, data: Vec<u8>) {
for i in 0..data.len() {
self.dtb[i] = data[i];
}
for i in data.len()..self.dtb.len() {
self.dtb[i] = 0;
}
}
pub fn tick(&mut self, mip: &mut u64) {
self.clint.tick(mip);
self.disk.tick(&mut self.memory);
self.uart.tick();
self.plic.tick(self.disk.is_interrupting(), self.uart.is_interrupting(), mip);
self.clock = self.clock.wrapping_add(1);
}
pub fn update_addressing_mode(&mut self, new_addressing_mode: AddressingMode) {
self.addressing_mode = new_addressing_mode;
}
pub fn update_privilege_mode(&mut self, mode: PrivilegeMode) {
self.privilege_mode = mode;
}
pub fn update_ppn(&mut self, ppn: u64) {
self.ppn = ppn;
}
fn get_effective_address(&self, address: u64) -> u64 {
match self.xlen {
Xlen::Bit32 => address & 0xffffffff,
Xlen::Bit64 => address
}
}
fn fetch(&mut self, v_address: u64) -> Result<u8, Trap> {
match self.translate_address(v_address, MemoryAccessType::Execute) {
Ok(p_address) => Ok(self.load_raw(p_address)),
Err(()) => return Err(Trap {
trap_type: TrapType::InstructionPageFault,
value: v_address
})
}
}
pub fn fetch_word(&mut self, v_address: u64) -> Result<u32, Trap> {
let width = 4;
match (v_address & 0xfff) <= (0x1000 - width) {
true => {
let effective_address = self.get_effective_address(v_address);
match self.translate_address(effective_address, MemoryAccessType::Execute) {
Ok(p_address) => Ok(self.load_word_raw(p_address)),
Err(()) => Err(Trap {
trap_type: TrapType::InstructionPageFault,
value: effective_address
})
}
},
false => {
let mut data = 0 as u32;
for i in 0..width {
match self.fetch(v_address.wrapping_add(i)) {
Ok(byte) => {
data |= (byte as u32) << (i * 8)
},
Err(e) => return Err(e)
};
}
Ok(data)
}
}
}
pub fn load(&mut self, v_address: u64) -> Result<u8, Trap> {
let effective_address = self.get_effective_address(v_address);
match self.translate_address(effective_address, MemoryAccessType::Read) {
Ok(p_address) => Ok(self.load_raw(p_address)),
Err(()) => Err(Trap {
trap_type: TrapType::LoadPageFault,
value: v_address
})
}
}
fn load_bytes(&mut self, v_address: u64, width: u64) -> Result<u64, Trap> {
assert!(width == 1 || width == 2 || width == 4 || width == 8,
"Width must be 1, 2, 4, or 8. {:X}", width);
match (v_address & 0xfff) <= (0x1000 - width) {
true => match self.translate_address(v_address, MemoryAccessType::Read) {
Ok(p_address) => {
match width {
1 => Ok(self.load_raw(p_address) as u64),
2 => Ok(self.load_halfword_raw(p_address) as u64),
4 => Ok(self.load_word_raw(p_address) as u64),
8 => Ok(self.load_doubleword_raw(p_address)),
_ => panic!("Width must be 1, 2, 4, or 8. {:X}", width)
}
},
Err(()) => Err(Trap {
trap_type: TrapType::LoadPageFault,
value: v_address
})
},
false => {
let mut data = 0 as u64;
for i in 0..width {
match self.load(v_address.wrapping_add(i)) {
Ok(byte) => {
data |= (byte as u64) << (i * 8)
},
Err(e) => return Err(e)
};
}
Ok(data)
}
}
}
pub fn load_halfword(&mut self, v_address: u64) -> Result<u16, Trap> {
match self.load_bytes(v_address, 2) {
Ok(data) => Ok(data as u16),
Err(e) => Err(e)
}
}
pub fn load_word(&mut self, v_address: u64) -> Result<u32, Trap> {
match self.load_bytes(v_address, 4) {
Ok(data) => Ok(data as u32),
Err(e) => Err(e)
}
}
pub fn load_doubleword(&mut self, v_address: u64) -> Result<u64, Trap> {
match self.load_bytes(v_address, 8) {
Ok(data) => Ok(data as u64),
Err(e) => Err(e)
}
}
pub fn store(&mut self, v_address: u64, value: u8) -> Result<(), Trap> {
match self.translate_address(v_address, MemoryAccessType::Write) {
Ok(p_address) => {
self.store_raw(p_address, value);
Ok(())
},
Err(()) => Err(Trap {
trap_type: TrapType::StorePageFault,
value: v_address
})
}
}
fn store_bytes(&mut self, v_address: u64, value: u64, width: u64) -> Result<(), Trap> {
assert!(width == 1 || width == 2 || width == 4 || width == 8,
"Width must be 1, 2, 4, or 8. {:X}", width);
match (v_address & 0xfff) <= (0x1000 - width) {
true => match self.translate_address(v_address, MemoryAccessType::Write) {
Ok(p_address) => {
match width {
1 => self.store_raw(p_address, value as u8),
2 => self.store_halfword_raw(p_address, value as u16),
4 => self.store_word_raw(p_address, value as u32),
8 => self.store_doubleword_raw(p_address, value),
_ => panic!("Width must be 1, 2, 4, or 8. {:X}", width)
}
Ok(())
},
Err(()) => Err(Trap {
trap_type: TrapType::StorePageFault,
value: v_address
})
},
false => {
for i in 0..width {
match self.store(v_address.wrapping_add(i), ((value >> (i * 8)) & 0xff) as u8) {
Ok(()) => {},
Err(e) => return Err(e)
}
}
Ok(())
}
}
}
pub fn store_halfword(&mut self, v_address: u64, value: u16) -> Result<(), Trap> {
self.store_bytes(v_address, value as u64, 2)
}
pub fn store_word(&mut self, v_address: u64, value: u32) -> Result<(), Trap> {
self.store_bytes(v_address, value as u64, 4)
}
pub fn store_doubleword(&mut self, v_address: u64, value: u64) -> Result<(), Trap> {
self.store_bytes(v_address, value as u64, 8)
}
fn load_raw(&mut self, p_address: u64) -> u8 {
let effective_address = self.get_effective_address(p_address);
match effective_address >= DRAM_BASE {
true => self.memory.read_byte(effective_address),
false => match effective_address {
0x00001020..=0x00001fff => self.dtb[effective_address as usize - 0x1020],
0x02000000..=0x0200ffff => self.clint.load(effective_address),
0x0C000000..=0x0fffffff => self.plic.load(effective_address),
0x10000000..=0x100000ff => self.uart.load(effective_address),
0x10001000..=0x10001FFF => self.disk.load(effective_address),
_ => panic!("Unknown memory mapping {:X}.", effective_address)
}
}
}
fn load_halfword_raw(&mut self, p_address: u64) -> u16 {
let effective_address = self.get_effective_address(p_address);
match effective_address >= DRAM_BASE && effective_address.wrapping_add(1) > effective_address {
true => self.memory.read_halfword(effective_address),
false => {
let mut data = 0 as u16;
for i in 0..2 {
data |= (self.load_raw(effective_address.wrapping_add(i)) as u16) << (i * 8)
}
data
}
}
}
pub fn load_word_raw(&mut self, p_address: u64) -> u32 {
let effective_address = self.get_effective_address(p_address);
match effective_address >= DRAM_BASE && effective_address.wrapping_add(3) > effective_address {
true => self.memory.read_word(effective_address),
false => {
let mut data = 0 as u32;
for i in 0..4 {
data |= (self.load_raw(effective_address.wrapping_add(i)) as u32) << (i * 8)
}
data
}
}
}
fn load_doubleword_raw(&mut self, p_address: u64) -> u64 {
let effective_address = self.get_effective_address(p_address);
match effective_address >= DRAM_BASE && effective_address.wrapping_add(7) > effective_address {
true => self.memory.read_doubleword(effective_address),
false => {
let mut data = 0 as u64;
for i in 0..8 {
data |= (self.load_raw(effective_address.wrapping_add(i)) as u64) << (i * 8)
}
data
}
}
}
pub fn store_raw(&mut self, p_address: u64, value: u8) {
let effective_address = self.get_effective_address(p_address);
match effective_address >= DRAM_BASE {
true => self.memory.write_byte(effective_address, value),
false => match effective_address {
0x02000000..=0x0200ffff => self.clint.store(effective_address, value),
0x0c000000..=0x0fffffff => self.plic.store(effective_address, value),
0x10000000..=0x100000ff => self.uart.store(effective_address, value),
0x10001000..=0x10001FFF => self.disk.store(effective_address, value),
_ => panic!("Unknown memory mapping {:X}.", effective_address)
}
};
}
fn store_halfword_raw(&mut self, p_address: u64, value: u16) {
let effective_address = self.get_effective_address(p_address);
match effective_address >= DRAM_BASE && effective_address.wrapping_add(1) > effective_address {
true => self.memory.write_halfword(effective_address, value),
false => {
for i in 0..2 {
self.store_raw(effective_address.wrapping_add(i), ((value >> (i * 8)) & 0xff) as u8);
}
}
}
}
fn store_word_raw(&mut self, p_address: u64, value: u32) {
let effective_address = self.get_effective_address(p_address);
match effective_address >= DRAM_BASE && effective_address.wrapping_add(3) > effective_address {
true => self.memory.write_word(effective_address, value),
false => {
for i in 0..4 {
self.store_raw(effective_address.wrapping_add(i), ((value >> (i * 8)) & 0xff) as u8);
}
}
}
}
fn store_doubleword_raw(&mut self, p_address: u64, value: u64) {
let effective_address = self.get_effective_address(p_address);
match effective_address >= DRAM_BASE && effective_address.wrapping_add(7) > effective_address {
true => self.memory.write_doubleword(effective_address, value),
false => {
for i in 0..8 {
self.store_raw(effective_address.wrapping_add(i), ((value >> (i * 8)) & 0xff) as u8);
}
}
}
}
pub fn validate_address(&mut self, v_address: u64) -> Result<bool, ()> {
let p_address = match self.translate_address(v_address, MemoryAccessType::DontCare) {
Ok(address) => address,
Err(()) => return Err(())
};
let effective_address = self.get_effective_address(p_address);
let valid = match effective_address >= DRAM_BASE {
true => self.memory.validate_address(effective_address),
false => match effective_address {
0x00001020..=0x00001fff => true,
0x02000000..=0x0200ffff => true,
0x0C000000..=0x0fffffff => true,
0x10000000..=0x100000ff => true,
0x10001000..=0x10001FFF => true,
_ => false
}
};
Ok(valid)
}
fn translate_address(&mut self, v_address: u64, access_type: MemoryAccessType) -> Result<u64, ()> {
let address = self.get_effective_address(v_address);
match self.addressing_mode {
AddressingMode::None => Ok(address),
AddressingMode::SV32 => match self.privilege_mode {
PrivilegeMode::User | PrivilegeMode::Supervisor => {
let vpns = [(address >> 12) & 0x3ff, (address >> 22) & 0x3ff];
self.traverse_page(address, 2 - 1, self.ppn, &vpns, access_type)
},
_ => Ok(address)
},
AddressingMode::SV39 => match self.privilege_mode {
PrivilegeMode::User | PrivilegeMode::Supervisor => {
let vpns = [(address >> 12) & 0x1ff, (address >> 21) & 0x1ff, (address >> 30) & 0x1ff];
self.traverse_page(address, 3 - 1, self.ppn, &vpns, access_type)
},
_ => Ok(address)
},
AddressingMode::SV48 => {
panic!("AddressingMode SV48 is not supported yet.");
}
}
}
fn traverse_page(&mut self, v_address: u64, level: u8, parent_ppn: u64,
vpns: &[u64], access_type: MemoryAccessType) -> Result<u64, ()> {
let pagesize = 4096;
let ptesize = match self.addressing_mode {
AddressingMode::SV32 => 4,
_ => 8
};
let pte_address = parent_ppn * pagesize + vpns[level as usize] * ptesize;
let pte = match self.addressing_mode {
AddressingMode::SV32 => self.load_word_raw(pte_address) as u64,
_ => self.load_doubleword_raw(pte_address)
};
let ppn = match self.addressing_mode {
AddressingMode::SV32 => (pte >> 10) & 0x3fffff,
_ => (pte >> 10) & 0xfffffffffff
};
let ppns = match self.addressing_mode {
AddressingMode::SV32 => [(pte >> 10) & 0x3ff, (pte >> 20) & 0xfff, 0 ],
AddressingMode::SV39 => [(pte >> 10) & 0x1ff, (pte >> 19) & 0x1ff, (pte >> 28) & 0x3ffffff],
_ => panic!()
};
let _rsw = (pte >> 8) & 0x3;
let d = (pte >> 7) & 1;
let a = (pte >> 6) & 1;
let _g = (pte >> 5) & 1;
let _u = (pte >> 4) & 1;
let x = (pte >> 3) & 1;
let w = (pte >> 2) & 1;
let r = (pte >> 1) & 1;
let v = pte & 1;
if v == 0 || (r == 0 && w == 1) {
return Err(());
}
if r == 0 && x == 0 {
return match level {
0 => Err(()),
_ => self.traverse_page(v_address, level - 1, ppn, vpns, access_type)
};
}
if a == 0 || (match access_type { MemoryAccessType::Write => d == 0, _ => false }) {
let new_pte = pte | (1 << 6) | (match access_type {
MemoryAccessType::Write => 1 << 7,
_ => 0
});
match self.addressing_mode {
AddressingMode::SV32 => self.store_word_raw(pte_address, new_pte as u32),
_ => self.store_doubleword_raw(pte_address, new_pte)
};
}
match access_type {
MemoryAccessType::Execute => {
if x == 0 {
return Err(());
}
},
MemoryAccessType::Read => {
if r == 0 {
return Err(());
}
},
MemoryAccessType::Write => {
if w == 0 {
return Err(());
}
},
_ => {}
};
let offset = v_address & 0xfff;
let p_address = match self.addressing_mode {
AddressingMode::SV32 => match level {
1 => {
if ppns[0] != 0 {
return Err(());
}
(ppns[1] << 22) | (vpns[0] << 12) | offset
},
0 => (ppn << 12) | offset,
_ => panic!()
},
_ => match level {
2 => {
if ppns[1] != 0 || ppns[0] != 0 {
return Err(());
}
(ppns[2] << 30) | (vpns[1] << 21) | (vpns[0] << 12) | offset
},
1 => {
if ppns[0] != 0 {
return Err(());
}
(ppns[2] << 30) | (ppns[1] << 21) | (vpns[0] << 12) | offset
},
0 => (ppn << 12) | offset,
_ => panic!()
},
};
Ok(p_address)
}
pub fn get_clint(&self) -> &Clint {
&self.clint
}
pub fn get_mut_clint(&mut self) -> &mut Clint {
&mut self.clint
}
pub fn get_mut_uart(&mut self) -> &mut Uart {
&mut self.uart
}
}
pub struct MemoryWrapper {
memory: Memory
}
impl MemoryWrapper {
fn new() -> Self {
MemoryWrapper {
memory: Memory::new()
}
}
fn init(&mut self, capacity: u64) {
self.memory.init(capacity);
}
pub fn read_byte(&mut self, p_address: u64) -> u8 {
assert!(p_address >= DRAM_BASE, "Memory address must equals to or bigger than DRAM_BASE. {:X}", p_address);
self.memory.read_byte(p_address - DRAM_BASE)
}
pub fn read_halfword(&mut self, p_address: u64) -> u16 {
assert!(p_address >= DRAM_BASE && p_address.wrapping_add(1) >= DRAM_BASE,
"Memory address must equals to or bigger than DRAM_BASE. {:X}", p_address);
self.memory.read_halfword(p_address - DRAM_BASE)
}
pub fn read_word(&mut self, p_address: u64) -> u32 {
assert!(p_address >= DRAM_BASE && p_address.wrapping_add(3) >= DRAM_BASE,
"Memory address must equals to or bigger than DRAM_BASE. {:X}", p_address);
self.memory.read_word(p_address - DRAM_BASE)
}
pub fn read_doubleword(&mut self, p_address: u64) -> u64 {
assert!(p_address >= DRAM_BASE && p_address.wrapping_add(7) >= DRAM_BASE,
"Memory address must equals to or bigger than DRAM_BASE. {:X}", p_address);
self.memory.read_doubleword(p_address - DRAM_BASE)
}
pub fn write_byte(&mut self, p_address: u64, value: u8) {
assert!(p_address >= DRAM_BASE, "Memory address must equals to or bigger than DRAM_BASE. {:X}", p_address);
self.memory.write_byte(p_address - DRAM_BASE, value)
}
pub fn write_halfword(&mut self, p_address: u64, value: u16) {
assert!(p_address >= DRAM_BASE && p_address.wrapping_add(1) >= DRAM_BASE,
"Memory address must equals to or bigger than DRAM_BASE. {:X}", p_address);
self.memory.write_halfword(p_address - DRAM_BASE, value)
}
pub fn write_word(&mut self, p_address: u64, value: u32) {
assert!(p_address >= DRAM_BASE && p_address.wrapping_add(3) >= DRAM_BASE,
"Memory address must equals to or bigger than DRAM_BASE. {:X}", p_address);
self.memory.write_word(p_address - DRAM_BASE, value)
}
pub fn write_doubleword(&mut self, p_address: u64, value: u64) {
assert!(p_address >= DRAM_BASE && p_address.wrapping_add(7) >= DRAM_BASE,
"Memory address must equals to or bigger than DRAM_BASE. {:X}", p_address);
self.memory.write_doubleword(p_address - DRAM_BASE, value)
}
pub fn validate_address(&self, address: u64) -> bool {
self.memory.validate_address(address)
}
}
const DTB_CONTENT_SIZE: usize = 400;
const DTB_CONTENT: [u32; DTB_CONTENT_SIZE] = [
0xedfe0dd0, 0x3e060000, 0x38000000, 0x3c050000,
0x28000000, 0x11000000, 0x10000000, 0x00000000,
0x02010000, 0x04050000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x01000000, 0x00000000,
0x03000000, 0x04000000, 0x00000000, 0x02000000,
0x03000000, 0x04000000, 0x0f000000, 0x02000000,
0x03000000, 0x0d000000, 0x1b000000, 0x63736972,
0x69762d76, 0x6f697472, 0x00000000, 0x03000000,
0x12000000, 0x26000000, 0x63736972, 0x69762d76,
0x6f697472, 0x6d65712c, 0x00000075, 0x01000000,
0x736f6863, 0x00006e65, 0x03000000, 0x1f000000,
0x2c000000, 0x746f6f72, 0x65642f3d, 0x64762f76,
0x6f722061, 0x6e6f6320, 0x656c6f73, 0x7974743d,
0x00003035, 0x03000000, 0x0f000000, 0x35000000,
0x7261752f, 0x30314074, 0x30303030, 0x00003030,
0x02000000, 0x01000000, 0x74726175, 0x30303140,
0x30303030, 0x00000030, 0x03000000, 0x04000000,
0x41000000, 0x0a000000, 0x03000000, 0x04000000,
0x4c000000, 0x03000000, 0x03000000, 0x04000000,
0x5d000000, 0x00403800, 0x03000000, 0x10000000,
0x6d000000, 0x00000000, 0x00000010, 0x00000000,
0x00010000, 0x03000000, 0x09000000, 0x1b000000,
0x3631736e, 0x61303535, 0x00000000, 0x02000000,
0x01000000, 0x74726976, 0x6d5f6f69, 0x406f696d,
0x30303031, 0x30303031, 0x00000000, 0x03000000,
0x04000000, 0x41000000, 0x01000000, 0x03000000,
0x04000000, 0x4c000000, 0x03000000, 0x03000000,
0x10000000, 0x6d000000, 0x00000000, 0x00100010,
0x00000000, 0x00100000, 0x03000000, 0x0c000000,
0x1b000000, 0x74726976, 0x6d2c6f69, 0x006f696d,
0x02000000, 0x01000000, 0x73757063, 0x00000000,
0x03000000, 0x04000000, 0x00000000, 0x01000000,
0x03000000, 0x04000000, 0x0f000000, 0x00000000,
0x03000000, 0x04000000, 0x71000000, 0x80969800,
0x01000000, 0x2d757063, 0x0070616d, 0x01000000,
0x73756c63, 0x30726574, 0x00000000, 0x01000000,
0x65726f63, 0x00000030, 0x03000000, 0x04000000,
0x84000000, 0x01000000, 0x02000000, 0x02000000,
0x02000000, 0x01000000, 0x40757063, 0x00000030,
0x03000000, 0x04000000, 0x88000000, 0x01000000,
0x03000000, 0x04000000, 0x90000000, 0x00757063,
0x03000000, 0x04000000, 0x6d000000, 0x00000000,
0x03000000, 0x05000000, 0x9c000000, 0x79616b6f,
0x00000000, 0x03000000, 0x06000000, 0x1b000000,
0x63736972, 0x00000076, 0x03000000, 0x0d000000,
0xa3000000, 0x34367672, 0x66616d69, 0x75736364,
0x00000000, 0x03000000, 0x0b000000, 0xad000000,
0x63736972, 0x76732c76, 0x00003933, 0x01000000,
0x65746e69, 0x70757272, 0x6f632d74, 0x6f72746e,
0x72656c6c, 0x00000000, 0x03000000, 0x04000000,
0xb6000000, 0x01000000, 0x03000000, 0x00000000,
0xc7000000, 0x03000000, 0x0f000000, 0x1b000000,
0x63736972, 0x70632c76, 0x6e692d75, 0x00006374,
0x03000000, 0x04000000, 0x88000000, 0x02000000,
0x02000000, 0x02000000, 0x02000000, 0x01000000,
0x6f6d656d, 0x38407972, 0x30303030, 0x00303030,
0x03000000, 0x07000000, 0x90000000, 0x6f6d656d,
0x00007972, 0x03000000, 0x10000000, 0x6d000000,
0x00000000, 0x00000080, 0x00000000, 0x00000008,
0x02000000, 0x01000000, 0x00636f73, 0x03000000,
0x04000000, 0x00000000, 0x02000000, 0x03000000,
0x04000000, 0x0f000000, 0x02000000, 0x03000000,
0x0b000000, 0x1b000000, 0x706d6973, 0x622d656c,
0x00007375, 0x03000000, 0x00000000, 0xdc000000,
0x01000000, 0x65746e69, 0x70757272, 0x6f632d74,
0x6f72746e, 0x72656c6c, 0x30306340, 0x30303030,
0x00000000, 0x03000000, 0x04000000, 0x88000000,
0x03000000, 0x03000000, 0x04000000, 0xe3000000,
0x35000000, 0x03000000, 0x10000000, 0x6d000000,
0x00000000, 0x0000000c, 0x00000000, 0x00000004,
0x03000000, 0x10000000, 0xee000000, 0x02000000,
0x0b000000, 0x02000000, 0x09000000, 0x03000000,
0x00000000, 0xc7000000, 0x03000000, 0x0c000000,
0x1b000000, 0x63736972, 0x6c702c76, 0x00306369,
0x03000000, 0x04000000, 0xb6000000, 0x01000000,
0x03000000, 0x04000000, 0x00000000, 0x00000000,
0x02000000, 0x01000000, 0x6e696c63, 0x30324074,
0x30303030, 0x00000030, 0x03000000, 0x10000000,
0xee000000, 0x02000000, 0x03000000, 0x02000000,
0x07000000, 0x03000000, 0x10000000, 0x6d000000,
0x00000000, 0x00000002, 0x00000000, 0x00000100,
0x03000000, 0x0d000000, 0x1b000000, 0x63736972,
0x6c632c76, 0x30746e69, 0x00000000, 0x02000000,
0x02000000, 0x02000000, 0x09000000, 0x64646123,
0x73736572, 0x6c65632d, 0x2300736c, 0x657a6973,
0x6c65632d, 0x6300736c, 0x61706d6f, 0x6c626974,
0x6f6d0065, 0x006c6564, 0x746f6f62, 0x73677261,
0x64747300, 0x2d74756f, 0x68746170, 0x746e6900,
0x75727265, 0x00737470, 0x65746e69, 0x70757272,
0x61702d74, 0x746e6572, 0x6f6c6300, 0x662d6b63,
0x75716572, 0x79636e65, 0x67657200, 0x6d697400,
0x73616265, 0x72662d65, 0x65757165, 0x0079636e,
0x00757063, 0x6e616870, 0x00656c64, 0x69766564,
0x745f6563, 0x00657079, 0x74617473, 0x72007375,
0x76637369, 0x6173692c, 0x756d6d00, 0x7079742d,
0x69230065, 0x7265746e, 0x74707572, 0x6c65632d,
0x6900736c, 0x7265746e, 0x74707572, 0x6e6f632d,
0x6c6f7274, 0x0072656c, 0x676e6172, 0x72007365,
0x76637369, 0x65646e2c, 0x6e690076, 0x72726574,
0x73747075, 0x7478652d, 0x65646e65, 0x00000064,
];
fn load_default_dtb_content(dtb: &mut Vec<u8>) {
for i in 0..DTB_CONTENT_SIZE {
dtb[i * 4] = DTB_CONTENT[i] as u8;
dtb[i * 4 + 1] = (DTB_CONTENT[i] >> 8) as u8;
dtb[i * 4 + 2] = (DTB_CONTENT[i] >> 16) as u8;
dtb[i * 4 + 3] = (DTB_CONTENT[i] >> 24) as u8;
}
}