summaryrefslogtreecommitdiff
path: root/src/acpi/acpigen.c
diff options
context:
space:
mode:
authorFelix Held <felix-coreboot@felixheld.de>2023-11-10 19:57:27 +0100
committerFelix Held <felix-coreboot@felixheld.de>2023-11-15 13:52:44 +0000
commita6f7459f38195377d7fddcf39d241bd7f0027a1c (patch)
tree145d5796beeb757c4717236c29ad6d8a003e6a81 /src/acpi/acpigen.c
parent87c42e870da871b8a866e07f5421a8711e988890 (diff)
acpi/acpigen: rework acpigen_pop_len for different size PkgLength
Previously acpigen_pop_len always wrote a 3 byte PkgLength to the 3 bytes reserved by acpigen_write_len_f. After this patch acpigen_pop_len encodes PkgLength in 1-3 bytes depending on the PkgLength. When less than the 3 bytes that were previously reserved in the corresponding acpigen_write_len_f call are needed for PkgLength, the payload data will be moved back by the number of reserved bytes that aren't needed for the PkgLength. This fixes the problem that the Windows AML parser doesn't like a 3 byte PkgLength being used for the size of the buffer containing UTF-16 strings when the length could be encoded in a single PkgLength byte. In that case, Windows previously ignored the whole SSDT containing this larger than necessary PkgLength encoding. It should however be noted that the ACPI 6.4 spec doesn't specify if it's required to always use the most compact possible encoding of the PkgLength or not. Since iasl generates the shortest possible PkgLength encoding, it's also a good idea to make coreboot's acpigen do the same although it's not required by the specification. With this patch applied, Windows still boots on Mandolin and the time it takes to write the tables doesn't change. To measure the times, the log level in bs_sample_time was increased to BIOS_CRIT and the console log level was increased to BIOS_CRIT too to only get those times as output. BS: BS_WRITE_TABLES run times (exec / console): 8 / 0 ms Signed-off-by: Felix Held <felix-coreboot@felixheld.de> Change-Id: Ib897b08a05a7cdc52902d51364246c260ea1f206 Reviewed-on: https://review.coreboot.org/c/coreboot/+/79002 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Matt DeVillier <matt.devillier@gmail.com> Reviewed-by: Nico Huber <nico.h@gmx.de> Reviewed-by: Jérémy Compostella <jeremy.compostella@intel.com>
Diffstat (limited to 'src/acpi/acpigen.c')
-rw-r--r--src/acpi/acpigen.c53
1 files changed, 47 insertions, 6 deletions
diff --git a/src/acpi/acpigen.c b/src/acpi/acpigen.c
index 57f0d10488..e5d76ba58e 100644
--- a/src/acpi/acpigen.c
+++ b/src/acpi/acpigen.c
@@ -38,16 +38,57 @@ void acpigen_write_len_f(void)
void acpigen_pop_len(void)
{
- int len;
+ size_t len;
ASSERT(ltop > 0)
char *p = len_stack[--ltop];
len = gencurrent - p;
ASSERT(len <= ACPIGEN_MAXLEN)
- /* generate store length for 0xfffff max */
- p[0] = (0x80 | (len & 0xf));
- p[1] = (len >> 4 & 0xff);
- p[2] = (len >> 12 & 0xff);
-
+ const size_t payload_len = len - 3;
+
+ if (len <= 0x3f + 2) {
+ /* PkgLength of up to 0x3f can be encoded in one PkgLength byte instead of the
+ reserved 3 bytes. Since only 1 PkgLength byte will be written, the payload
+ data needs to be moved by 2 bytes */
+ memmove(&p[1], &p[3], payload_len);
+ /* Adjust the PkgLength to take into account that we only use 1 of the 3
+ reserved bytes */
+ len -= 2;
+ /* The two most significant bits of PkgLength get the value of 0 to indicate
+ there are no additional PkgLength bytes. In this case the single PkgLength
+ byte encodes the length in its lower 6 bits */
+ p[0] = len;
+ /* Adjust pointer for next ACPI bytecode byte */
+ acpigen_set_current(p + len);
+ } else if (len <= 0xfff + 1) {
+ /* PkgLength of up to 0xfff can be encoded in 2 PkgLength bytes instead of the
+ reserved 3 bytes. Since only 2 PkgLength bytes will be written, the payload
+ data needs to be moved by 1 byte */
+ memmove(&p[2], &p[3], payload_len);
+ /* Adjust the PkgLength to take into account that we only use 2 of the 3
+ reserved bytes */
+ len -= 1;
+ /* The two most significant bits of PkgLength get the value of 1 to indicate
+ there's a second PkgLength byte. The lower 4 bits of the first PkgLength
+ byte and the second PkgLength byte encode the length */
+ p[0] = (0x1 << 6 | (len & 0xf));
+ p[1] = (len >> 4 & 0xff);
+ /* Adjust pointer for next ACPI bytecode byte */
+ acpigen_set_current(p + len);
+ } else if (len <= 0xfffff) {
+ /* PkgLength of up to 0xfffff can be encoded in 3 PkgLength bytes. Since this
+ is the amount of reserved bytes, no need to move the payload in this case */
+ /* The two most significant bits of PkgLength get the value of 2 to indicate
+ there are two more PkgLength bytes following the first one. The lower 4 bits
+ of the first PkgLength byte and the two following PkgLength bytes encode the
+ length */
+ p[0] = (0x2 << 6 | (len & 0xf));
+ p[1] = (len >> 4 & 0xff);
+ p[2] = (len >> 12 & 0xff);
+ /* No need to adjust pointer for next ACPI bytecode byte */
+ } else {
+ /* The case of PkgLength up to 0xfffffff isn't supported at the moment */
+ printk(BIOS_ERR, "%s: package length exceeds maximum of 0xfffff.\n", __func__);
+ }
}
void acpigen_set_current(char *curr)