Aaron Durbin (adurbin(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/13479
-gerrit
commit 4117a87c5787ff4586a4d65e5276f287afb45589
Author: Aaron Durbin <adurbin(a)chromium.org>
Date: Tue Jan 26 17:08:56 2016 -0600
util/cbfstool: add 'compact' command
While assembling CBFS images within the RW slots on Chrome OS
machines the current approach is to 'cbfstool copy' from the
RO CBFS to each RW CBFS. Additional fixups are required such
as removing unneeded files from the RW CBFS (e.g. verstage)
as well as removing and adding back files with the proper
arguments (FSP relocation as well as romstage XIP relocation).
This ends up leaving holes in the RW CBFS. To speed up RW
CBFS slot hashing it's beneficial to pack all non-empty files
together at the beginning of the CBFS. Therefore, provide
the 'compact' command which bubbles all the empty entries to
the end of the CBFS.
Change-Id: I8311172d71a2ccfccab384f8286cf9f21a17dec9
Signed-off-by: Aaron Durbin <adurbin(a)chromium.org>
---
util/cbfstool/cbfs_image.c | 121 +++++++++++++++++++++++++++++++++++++++++++++
util/cbfstool/cbfs_image.h | 4 ++
util/cbfstool/cbfstool.c | 13 +++++
3 files changed, 138 insertions(+)
diff --git a/util/cbfstool/cbfs_image.c b/util/cbfstool/cbfs_image.c
index b98df8a..0e0eabe 100644
--- a/util/cbfstool/cbfs_image.c
+++ b/util/cbfstool/cbfs_image.c
@@ -440,6 +440,127 @@ int cbfs_copy_instance(struct cbfs_image *image, struct buffer *dst)
return 0;
}
+static size_t cbfs_file_entry_metadata_size(const struct cbfs_file *f)
+{
+ return ntohl(f->offset);
+}
+
+static size_t cbfs_file_entry_data_size(const struct cbfs_file *f)
+{
+ return ntohl(f->len);
+}
+
+static size_t cbfs_file_entry_size(const struct cbfs_file *f)
+{
+ return cbfs_file_entry_metadata_size(f) + cbfs_file_entry_data_size(f);
+}
+
+int cbfs_compact_instance(struct cbfs_image *image)
+{
+ assert(image);
+
+ struct cbfs_file *prev;
+ struct cbfs_file *cur;
+
+ /* The prev entry will always be an empty entry. */
+ prev = NULL;
+
+ /*
+ * Note: this function does not honor alignment or fixed location files.
+ * It's behavior is akin to cbfs_copy_instance() in that it expects
+ * the caller to understand the ramifications of compacting a
+ * fragmented CBFS image.
+ */
+
+ for (cur = cbfs_find_first_entry(image);
+ cur && cbfs_is_valid_entry(image, cur);
+ cur = cbfs_find_next_entry(image, cur)) {
+ size_t prev_size;
+ size_t cur_size;
+ size_t empty_metadata_size;
+ size_t spill_size;
+ uint32_t type = htonl(cur->type);
+
+ /* Current entry is empty. Kepp track of it. */
+ if ((type == htonl(CBFS_COMPONENT_NULL)) ||
+ (type == htonl(CBFS_COMPONENT_DELETED))) {
+ prev = cur;
+ continue;
+ }
+
+ /* Need to ensure the previous entry is an empty one. */
+ if (prev == NULL)
+ continue;
+
+ /* At this point prev is an empty entry. Put the non-empty
+ * file in prev's location. Then add a new emptry entry. This
+ * essentialy bubbles empty entries towards the end. */
+
+ prev_size = cbfs_file_entry_size(prev);
+ cur_size = cbfs_file_entry_size(cur);
+
+ /*
+ * Adjust the empty file size by the actual space occupied
+ * bewtween the beginning of the empty file and the non-empty
+ * file.
+ */
+ prev_size += (cbfs_get_entry_addr(image, cur) -
+ cbfs_get_entry_addr(image, prev)) - prev_size;
+
+ /* Move the non-empty file over the empty file. */
+ memmove(prev, cur, cur_size);
+
+ /*
+ * Get location of the empty file. Note that since prev was
+ * overwritten with the non-empty file the previously moved
+ * file needs to be used to calculate the empty file's location.
+ */
+ cur = cbfs_find_next_entry(image, prev);
+
+ /*
+ * The total space to work with for swapping the 2 entries
+ * consists of the 2 files' sizes combined. However, the
+ * cbfs_file entries start on CBFS_ALIGNMENT boundaries.
+ * Because of this the empty file size may end up smaller
+ * because of the non-empty file's metadata and data length.
+ *
+ * Calculate the spill size which is the amount of data lost
+ * due to the alignment constraints after moving the non-empty
+ * file.
+ */
+ spill_size = (cbfs_get_entry_addr(image, cur) -
+ cbfs_get_entry_addr(image, prev)) - cur_size;
+
+ empty_metadata_size = cbfs_calculate_file_header_size("");
+
+ /* Check if new empty size can contain the metadata. */
+ if (empty_metadata_size + spill_size > prev_size) {
+ ERROR("Unable to swap '%s' with prev empty entry.\n",
+ prev->filename);
+ return 1;
+ }
+
+ /* Update the empty file's size. */
+ prev_size -= spill_size + empty_metadata_size;
+
+ /* Create new empty file. */
+ cbfs_create_empty_entry(cur, CBFS_COMPONENT_NULL,
+ prev_size, "");
+
+ /* Merge any potential empty entries together. */
+ cbfs_walk(image, cbfs_merge_empty_entry, NULL);
+
+ /*
+ * Since current switched to an empty file keep track of it.
+ * Even if any empty files were merged the empty entry still
+ * starts at previously calculated location.
+ */
+ prev = cur;
+ }
+
+ return 0;
+}
+
int cbfs_image_delete(struct cbfs_image *image)
{
if (image == NULL)
diff --git a/util/cbfstool/cbfs_image.h b/util/cbfstool/cbfs_image.h
index 38510d2..0d7877a 100644
--- a/util/cbfstool/cbfs_image.h
+++ b/util/cbfstool/cbfs_image.h
@@ -76,6 +76,10 @@ int cbfs_image_from_buffer(struct cbfs_image *out, struct buffer *in,
* Will not succeed on new-style images without a master header. */
int cbfs_copy_instance(struct cbfs_image *image, struct buffer *dst);
+/* Compact a fragmented CBFS image by placing all the non-empty files at the
+ * beginning of the image. Returns 0 on success, otherwise non-zero. */
+int cbfs_compact_instance(struct cbfs_image *image);
+
/* Releases the CBFS image. Returns 0 on success, otherwise non-zero. */
int cbfs_image_delete(struct cbfs_image *image);
diff --git a/util/cbfstool/cbfstool.c b/util/cbfstool/cbfstool.c
index 13a9956..5be2d65 100644
--- a/util/cbfstool/cbfstool.c
+++ b/util/cbfstool/cbfstool.c
@@ -1054,6 +1054,16 @@ static int cbfs_copy(void)
return cbfs_copy_instance(&src_image, param.image_region);
}
+static int cbfs_compact(void)
+{
+ struct cbfs_image image;
+ if (cbfs_image_from_buffer(&image, param.image_region,
+ param.headeroffset))
+ return 1;
+ WARN("Compacting a CBFS doesn't honor alignment or fixed addresses!\n");
+ return cbfs_compact_instance(&image);
+}
+
static const struct command commands[] = {
{"add", "H:r:f:n:t:c:b:a:vA:gh?", cbfs_add, true, true},
{"add-flat-binary", "H:r:f:n:l:e:c:b:vA:gh?", cbfs_add_flat_binary,
@@ -1064,6 +1074,7 @@ static const struct command commands[] = {
true, true},
{"add-int", "H:r:i:n:b:vgh?", cbfs_add_integer, true, true},
{"add-master-header", "H:r:vh?", cbfs_add_master_header, true, true},
+ {"compact", "r:h?", cbfs_compact, true, true},
{"copy", "r:R:h?", cbfs_copy, true, true},
{"create", "M:r:s:B:b:H:o:m:vh?", cbfs_create, true, true},
{"hashcbfs", "r:R:A:vh?", cbfs_hash, true, true},
@@ -1198,6 +1209,8 @@ static void usage(char *name)
"Add a legacy CBFS master header\n"
" remove [-r image,regions] -n NAME "
"Remove a component\n"
+ " compact -r image,regions "
+ "Defragment CBFS image.\n"
" copy -r image,regions -R source-region "
"Create a copy (duplicate) cbfs instance in fmap\n"
" create -m ARCH -s size [-b bootblock offset] \\\n"
Patrick Rudolph (siro(a)das-labor.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/11917
-gerrit
commit 235a55c2bcc38df41478a76d283352c86f15d9da
Author: Patrick Rudolph <siro(a)das-labor.org>
Date: Thu Oct 15 11:09:15 2015 +0200
nb/intel/sandybridge: Start PEG link training
Issue observed:
The PCIe Root port shows up in GNU/Linux but no PCIe device
is being detected.
Test system:
* Gigabyte GA-B75M-D3H (Intel Pentium CPU G2130)
* Lenovo T530 (Intel Core i5-3320M CPU)
Problem description:
The PEG Root port link training on Ivy Bridge needs to be manually started.
Problem solution:
The bits are set in early_init to meet PCIe reset timeout of 100msec.
The bits should be set in PCI device enable function, but this causes the
PCI enumeration to not detect the card, as it's still booting. Adding
a fixed delay of 100msec resolves this problem, but this would
increase boot time.
Don't run the code on MRC path as it has its own PEG initilization code.
Tested with:
* Nvidia NVS 5400M (PCIe2)
* ATI Radeon HD4780 (PCIe2)
* Nvidia GeForce 8600 GT (PCIe1)
Untested:
* PCIe3 devices
Final test results:
The PEG device shows up under GNU/Linux and can be used without issues.
Change-Id: Id8cfc43e5c4630b0ac217d98bb857c3308e6015b
Signed-off-by: Patrick Rudolph <siro(a)das-labor.org>
---
src/northbridge/intel/sandybridge/early_init.c | 42 ++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/src/northbridge/intel/sandybridge/early_init.c b/src/northbridge/intel/sandybridge/early_init.c
index 81bf9d5..97a2cef 100644
--- a/src/northbridge/intel/sandybridge/early_init.c
+++ b/src/northbridge/intel/sandybridge/early_init.c
@@ -148,6 +148,39 @@ static void sandybridge_setup_graphics(void)
MCHBAR32(0x5418) = reg32;
}
+/* PEG on IvyBridge+ needs a special startup sequence.
+ * As the MRC has its own initialization code skip it.
+ */
+static void start_peg_link_training(void)
+{
+#ifdef CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE
+ u32 tmp;
+ u32 deven;
+
+ deven = pci_read_config32(PCI_DEV(0, 0, 0), DEVEN);
+
+ if (deven & DEVEN_PEG10) {
+ tmp = pci_read_config32(PCI_DEV(0, 1, 0), 0xC24) & ~(1 << 16);
+ pci_write_config32(PCI_DEV(0, 1, 0), 0xC24, tmp | (1 << 5));
+ }
+
+ if (deven & DEVEN_PEG11) {
+ tmp = pci_read_config32(PCI_DEV(0, 1, 1), 0xC24) & ~(1 << 16);
+ pci_write_config32(PCI_DEV(0, 1, 1), 0xC24, tmp | (1 << 5));
+ }
+
+ if (deven & DEVEN_PEG12) {
+ tmp = pci_read_config32(PCI_DEV(0, 1, 2), 0xC24) & ~(1 << 16);
+ pci_write_config32(PCI_DEV(0, 1, 2), 0xC24, tmp | (1 << 5));
+ }
+
+ if (deven & DEVEN_PEG60) {
+ tmp = pci_read_config32(PCI_DEV(0, 6, 0), 0xC24) & ~(1 << 16);
+ pci_write_config32(PCI_DEV(0, 6, 0), 0xC24, tmp | (1 << 5));
+ }
+#endif
+}
+
void sandybridge_early_initialization(int chipset_type)
{
u32 capid0_a;
@@ -177,6 +210,15 @@ void sandybridge_early_initialization(int chipset_type)
pci_write_config32(PCI_DEV(0, 0, 0), DEVEN, deven);
sandybridge_setup_graphics();
+
+ /* Write magic value to start PEG link training.
+ * This should be done in PCI device enumeration, but
+ * the PCIe specification requires to wait at least 100msec
+ * after reset for devices to come up.
+ * As we don't want to increase boot time, enable it early and
+ * assume the PEG is up as soon as PCI enumeration starts.
+ * TODO: use time stamps to ensure the timings are met */
+ start_peg_link_training();
}
void northbridge_romstage_finalize(int s3resume)
the following patch was just integrated into master:
commit 95bfcaecf9c054bd116b7f36339f8de595026f28
Author: Werner Zeh <werner.zeh(a)siemens.com>
Date: Mon Jan 25 12:47:20 2016 +0100
cbfstool: Fix broken alignment because of flashmap
With the introduction of flashmap cbfs alignment of files gets
broken because flashmap is located at the beginning of the flash
and cbfstool didn't take care about that offset.
This commit fixes the alignment in cbfs.
Change-Id: Idebb86d4c691b49a351a402ef79c62d31622c773
Signed-off-by: Werner Zeh <werner.zeh(a)siemens.com>
Reviewed-on: https://review.coreboot.org/13417
Reviewed-by: Aaron Durbin <adurbin(a)chromium.org>
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Georgi <pgeorgi(a)google.com>
See https://review.coreboot.org/13417 for details.
-gerrit