android_bootimage/
header.rs1use Section;
2use byteorder::{LittleEndian, ReadBytesExt};
3use quick_error::ResultExt;
4use std::io::{Error as IoError, Read, Seek, SeekFrom};
5
6pub const MAGIC_STR: &'static str = "ANDROID!";
7const MAGIC_SIZE: usize = 8;
8const PRODUCT_NAME_SIZE: usize = 24;
9const BOOT_ARGUMENTS_SIZE: usize = 512;
10const UNIQUE_ID_SIZE: usize = 32;
11const HEADER_SIZE: usize = 616;
12
13const SECTIONS: &'static [Section] = &[
15 Section::Header,
16 Section::Kernel,
17 Section::Ramdisk,
18 Section::Second,
19 Section::DeviceTree,
20];
21
22#[derive(Debug)]
24pub struct MagicHeader {
25 pub magic: [u8; MAGIC_SIZE],
27 pub kernel_size: u32,
29 pub kernel_load_address: u32,
31
32 pub ramdisk_size: u32,
34 pub ramdisk_load_address: u32,
36
37 pub second_size: u32,
39 pub second_load_address: u32,
41
42 pub device_tree_size: u32,
44 _reserved: u32,
46
47 pub kernel_tags_address: u32,
49 pub page_size: u32,
51 pub product_name: [u8; PRODUCT_NAME_SIZE],
53 pub boot_arguments: [[u8; BOOT_ARGUMENTS_SIZE / 16]; 16],
56 pub unique_id: [u8; UNIQUE_ID_SIZE],
58}
59
60impl MagicHeader {
61 pub fn read_from<R: ReadBytesExt>(
63 source: &mut R,
64 check_magic: bool,
65 ) -> Result<Self, MagicHeaderParseError> {
66 let header = MagicHeader {
67 magic: {
68 let mut buffer = [0; MAGIC_SIZE];
69 source.read_exact(&mut buffer)?;
70 buffer
71 },
72 kernel_size: source.read_u32::<LittleEndian>()?,
73 kernel_load_address: source.read_u32::<LittleEndian>()?,
74 ramdisk_size: source.read_u32::<LittleEndian>()?,
75 ramdisk_load_address: source.read_u32::<LittleEndian>()?,
76 second_size: source.read_u32::<LittleEndian>()?,
77 second_load_address: source.read_u32::<LittleEndian>()?,
78 device_tree_size: source.read_u32::<LittleEndian>()?,
79 _reserved: source.read_u32::<LittleEndian>()?,
80 kernel_tags_address: source.read_u32::<LittleEndian>()?,
81 page_size: source.read_u32::<LittleEndian>()?,
82 product_name: {
83 let mut buffer = [0; PRODUCT_NAME_SIZE];
84 source.read_exact(&mut buffer)?;
85 buffer
86 },
87 boot_arguments: unsafe {
88 use std::mem::transmute;
89 let mut buffer = [0; BOOT_ARGUMENTS_SIZE];
90 source.read_exact(&mut buffer)?;
91 transmute(buffer)
92 },
93 unique_id: {
94 let mut buffer = [0u8; UNIQUE_ID_SIZE];
95 source.read_exact(&mut buffer)?;
96 buffer
97 },
98 };
99
100 if check_magic && header.magic != MAGIC_STR.as_bytes() {
101 Err(MagicHeaderParseError::InvalidMagic(header))
102 } else {
103 Ok(header)
104 }
105 }
106
107 pub fn section_size(&self, section: Section) -> u64 {
109 match section {
110 Section::Header => HEADER_SIZE as u64,
111 Section::Kernel => self.kernel_size as u64,
112 Section::Ramdisk => self.ramdisk_size as u64,
113 Section::Second => self.second_size as u64,
114 Section::DeviceTree => self.device_tree_size as u64,
115 }
116 }
117
118 pub fn section_start(&self, section: Section) -> Result<u64, LocateSectionError> {
124 if self.page_size == 0 {
125 Err(LocateSectionError::NoPageSize)
126 } else {
127 let offset_in_pages: u64 = SECTIONS
128 .iter()
129 .cloned()
130 .take_while(|&i_section| i_section != section)
132 .map(|section| {
134 (self.section_size(section) + self.page_size as u64 - 1) / self.page_size as u64
135 })
136 .sum();
138
139 Ok(offset_in_pages * self.page_size as u64)
141 }
142 }
143
144 pub fn section_location(&self, section: Section) -> Result<(u64, u64), LocateSectionError> {
150 Ok((self.section_start(section)?, self.section_size(section)))
151 }
152
153 pub fn read_section_from<R: Read + Seek>(
159 &self,
160 source: &mut R,
161 section: Section,
162 ) -> Result<Vec<u8>, ReadSectionError> {
163 let (start, size) = self.section_location(section).context(section)?;
164 try!(source.seek(SeekFrom::Start(start)).context(section));
165 let mut data = vec![0u8; size as usize];
166 try!(source.read_exact(&mut data).context(section));
167 return Ok(data);
168 }
169
170 pub fn sections(&self) -> Vec<Section> {
173 SECTIONS
174 .iter()
175 .filter(|&§ion| self.section_size(section) > 0)
176 .cloned()
177 .collect()
178 }
179}
180
181quick_error! {
182 #[derive(Debug)]
183 pub enum MagicHeaderParseError {
184 Io(error: IoError) {
185 description("I/O error while parsing header")
186 display("I/O error while parsing header.")
187 cause(error)
188 from(error: IoError) -> (error)
189 }
190 InvalidMagic(header: MagicHeader) {
191 description("The header did not have the valid magic prefix")
192 display("The header did not have the valid '{}' magic prefix.", MAGIC_STR)
193 }
194 }
195}
196
197quick_error! {
198 #[derive(Debug)]
199 pub enum LocateSectionError {
200 NoPageSize {
201 description("The header's page size is zero")
202 display("The header's page size is 0.")
203 }
204 NoSection(section: Section) {
205 description("The section does not exist")
206 display("The '{}' section does not exist.", section)
207 }
208 }
209}
210quick_error! {
211 #[derive(Debug)]
212 pub enum ReadSectionError {
213 LocateSection(section: Section, cause: LocateSectionError) {
214 context(section: Section, cause: LocateSectionError) -> (section, cause)
215 description("Could not locate the section")
216 display("Cannot locate the '{}' section.", section)
217 cause(cause)
218 }
219 IoError(section: Section, cause: IoError) {
220 context(section: Section, cause: IoError) -> (section, cause)
221 description("I/O error while reading the section")
222 display("I/O error while reading the '{}' section.", section)
223 cause(cause)
224 }
225 }
226}