Skip to content

Commit 7f3deb5

Browse files
authored
Merge pull request #97 from jessebraham/fixes/partition-table
Fix bug where partition table offset is not used
2 parents e7a0f83 + 81131e4 commit 7f3deb5

File tree

3 files changed

+74
-27
lines changed

3 files changed

+74
-27
lines changed

espflash/src/error.rs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
1-
use crate::command::CommandType;
2-
use crate::image_format::ImageFormatId;
3-
use crate::partition_table::{SubType, Type};
4-
use crate::Chip;
1+
use std::{
2+
fmt::{Display, Formatter},
3+
io,
4+
};
5+
56
use miette::{Diagnostic, SourceOffset, SourceSpan};
67
use slip_codec::SlipError;
7-
use std::fmt::{Display, Formatter};
8-
use std::io;
98
use strum::VariantNames;
109
use thiserror::Error;
1110

11+
use crate::{
12+
command::CommandType,
13+
image_format::ImageFormatId,
14+
partition_table::{SubType, Type},
15+
Chip,
16+
};
17+
1218
#[derive(Error, Debug, Diagnostic)]
1319
#[non_exhaustive]
1420
pub enum Error {
@@ -308,6 +314,9 @@ pub enum PartitionTableError {
308314
InvalidSubType(#[from] InvalidSubTypeError),
309315
#[error(transparent)]
310316
#[diagnostic(transparent)]
317+
NoFactoryApp(#[from] NoFactoryAppError),
318+
#[error(transparent)]
319+
#[diagnostic(transparent)]
311320
UnalignedPartitionError(#[from] UnalignedPartitionError),
312321
}
313322

@@ -459,6 +468,25 @@ impl InvalidSubTypeError {
459468
}
460469
}
461470

471+
#[derive(Debug, Error, Diagnostic)]
472+
#[error("No factory app partition was found")]
473+
#[diagnostic(
474+
code(espflash::partition_table::no_factory_app),
475+
help("Partition table must contain a factory app partition")
476+
)]
477+
pub struct NoFactoryAppError {
478+
#[source_code]
479+
source_code: String,
480+
}
481+
482+
impl NoFactoryAppError {
483+
pub fn new(source: &str) -> Self {
484+
NoFactoryAppError {
485+
source_code: source.into(),
486+
}
487+
}
488+
}
489+
462490
#[derive(Debug, Error, Diagnostic)]
463491
#[error("Unaligned partition")]
464492
#[diagnostic(code(espflash::partition_table::unaligned))]

espflash/src/image_format/esp32bootloader.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,16 @@ impl<'a> Esp32BootloaderFormat<'a> {
121121
let hash = hasher.finalize();
122122
data.write_all(&hash)?;
123123

124+
// The default partition table contains the "factory" partition, and if a user
125+
// provides a partition table via command-line then the validation step confirms
126+
// this is present, so it's safe to unwrap.
127+
let factory_partition = partition_table.find("factory").unwrap();
128+
124129
let flash_segment = RomSegment {
125-
addr: params.app_addr,
130+
addr: factory_partition.offset(),
126131
data: Cow::Owned(data),
127132
};
133+
128134
Ok(Self {
129135
params,
130136
bootloader,

espflash/src/partition_table.rs

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1-
use crate::error::{
2-
CSVError, DuplicatePartitionsError, InvalidSubTypeError, OverlappingPartitionsError,
3-
PartitionTableError, UnalignedPartitionError,
1+
use std::{
2+
cmp::{max, min},
3+
fmt::{Display, Formatter, Write as _},
4+
io::Write,
5+
ops::Rem,
46
};
7+
58
use md5::{Context, Digest};
69
use regex::Regex;
710
use serde::{Deserialize, Deserializer, Serialize};
8-
use std::cmp::{max, min};
9-
use std::fmt::Write as _;
10-
use std::fmt::{Display, Formatter};
11-
use std::io::Write;
12-
use std::ops::Rem;
11+
12+
use crate::error::{
13+
CSVError, DuplicatePartitionsError, InvalidSubTypeError, NoFactoryAppError,
14+
OverlappingPartitionsError, PartitionTableError, UnalignedPartitionError,
15+
};
1316

1417
const MAX_PARTITION_LENGTH: usize = 0xC00;
1518
const PARTITION_TABLE_SIZE: usize = 0x1000;
@@ -28,16 +31,9 @@ impl Type {
2831
match self {
2932
Type::App => "'factory', 'ota_0' through 'ota_15' and 'test'".into(),
3033
Type::Data => {
34+
use DataType::*;
3135
let types = [
32-
DataType::Ota,
33-
DataType::Phy,
34-
DataType::Nvs,
35-
DataType::CoreDump,
36-
DataType::NvsKeys,
37-
DataType::EFuse,
38-
DataType::EspHttpd,
39-
DataType::Fat,
40-
DataType::Spiffs,
36+
Ota, Phy, Nvs, CoreDump, NvsKeys, EFuse, EspHttpd, Fat, Spiffs,
4137
];
4238

4339
let mut out = format!("'{}'", serde_plain::to_string(&types[0]).unwrap());
@@ -57,8 +53,7 @@ impl Type {
5753

5854
impl Display for Type {
5955
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
60-
let ser = serde_plain::to_string(self).unwrap();
61-
write!(f, "{}", ser)
56+
write!(f, "{}", serde_plain::to_string(self).unwrap())
6257
}
6358
}
6459

@@ -246,13 +241,18 @@ impl PartitionTable {
246241
Ok(())
247242
}
248243

244+
pub fn find(&self, name: &str) -> Option<&Partition> {
245+
self.partitions.iter().find(|&p| p.name == name)
246+
}
247+
249248
fn validate(&self, source: &str) -> Result<(), PartitionTableError> {
250249
for partition in &self.partitions {
251250
if let Some(line) = &partition.line {
252251
let expected_type = match partition.sub_type {
253252
SubType::App(_) => Type::App,
254253
SubType::Data(_) => Type::Data,
255254
};
255+
256256
if expected_type != partition.ty {
257257
return Err(InvalidSubTypeError::new(
258258
source,
@@ -262,6 +262,7 @@ impl PartitionTable {
262262
)
263263
.into());
264264
}
265+
265266
if partition.ty == Type::App && partition.offset.rem(0x10000) != 0 {
266267
return Err(UnalignedPartitionError::new(source, *line).into());
267268
}
@@ -277,12 +278,14 @@ impl PartitionTable {
277278
OverlappingPartitionsError::new(source, *line1, *line2).into()
278279
);
279280
}
281+
280282
if partition1.name == partition2.name {
281283
return Err(DuplicatePartitionsError::new(
282284
source, *line1, *line2, "name",
283285
)
284286
.into());
285287
}
288+
286289
if partition1.sub_type == partition2.sub_type {
287290
return Err(DuplicatePartitionsError::new(
288291
source, *line1, *line2, "sub-type",
@@ -294,14 +297,20 @@ impl PartitionTable {
294297
}
295298
}
296299

300+
if self.find("factory").is_none() {
301+
return Err(PartitionTableError::NoFactoryApp(NoFactoryAppError::new(
302+
source,
303+
)));
304+
}
305+
297306
Ok(())
298307
}
299308
}
300309

301310
const PARTITION_SIZE: usize = 32;
302311

303312
#[derive(Debug, Deserialize)]
304-
struct Partition {
313+
pub struct Partition {
305314
#[serde(deserialize_with = "deserialize_partition_name")]
306315
name: String,
307316
ty: Type,
@@ -358,6 +367,10 @@ impl Partition {
358367
Ok(())
359368
}
360369

370+
pub fn offset(&self) -> u32 {
371+
self.offset
372+
}
373+
361374
fn overlaps(&self, other: &Partition) -> bool {
362375
max(self.offset, other.offset) < min(self.offset + self.size, other.offset + other.size)
363376
}

0 commit comments

Comments
 (0)