Message ID | 20220506205605.359830-3-nikos.nikoleris@arm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | EFI and ACPI support for arm64 | expand |
On Fri, May 06, 2022 at 09:55:44PM +0100, Nikos Nikoleris wrote: > All ACPI table definitions are provided with precise definitions of > field sizes and offsets, make sure that no compiler optimization can > interfere with the memory layout of the corresponding structs. That seems like a reasonable thing to do. I'm wondering why Linux doesn't appear to do it. I see u-boot does, but not for all tables, which also makes me scratch my head... I see this patch packs every struct except rsdp_descriptor. Is there a reason it was left out? Another comment below > > Signed-off-by: Nikos Nikoleris <nikos.nikoleris@arm.com> > --- > lib/acpi.h | 11 ++++++++--- > x86/s3.c | 16 ++++------------ > 2 files changed, 12 insertions(+), 15 deletions(-) > > diff --git a/lib/acpi.h b/lib/acpi.h > index 1e89840..42a2c16 100644 > --- a/lib/acpi.h > +++ b/lib/acpi.h > @@ -3,6 +3,11 @@ > > #include "libcflat.h" > > +/* > + * All tables and structures must be byte-packed to match the ACPI > + * specification, since the tables are provided by the system BIOS > + */ > + > #define ACPI_SIGNATURE(c1, c2, c3, c4) \ > ((c1) | ((c2) << 8) | ((c3) << 16) | ((c4) << 24)) > > @@ -44,12 +49,12 @@ struct rsdp_descriptor { /* Root System Descriptor Pointer */ > struct acpi_table { > ACPI_TABLE_HEADER_DEF > char data[0]; > -}; > +} __attribute__ ((packed)); > > struct rsdt_descriptor_rev1 { > ACPI_TABLE_HEADER_DEF > u32 table_offset_entry[0]; > -}; > +} __attribute__ ((packed)); > > struct fadt_descriptor_rev1 > { > @@ -104,7 +109,7 @@ struct facs_descriptor_rev1 > u32 S4bios_f : 1; /* Indicates if S4BIOS support is present */ > u32 reserved1 : 31; /* Must be 0 */ > u8 reserved3 [40]; /* Reserved - must be zero */ > -}; > +} __attribute__ ((packed)); > > void set_efi_rsdp(struct rsdp_descriptor *rsdp); > void* find_acpi_table_addr(u32 sig); > diff --git a/x86/s3.c b/x86/s3.c The changes below in this file are unrelated, so they should be in a separate patch. However, I'm also curious why they're needed. I see that find_acpi_table_addr() can return NULL, so it doesn't seem like we should be removing the check, but instead changing the check to an assert. > index 378d37a..89d69fc 100644 > --- a/x86/s3.c > +++ b/x86/s3.c > @@ -2,15 +2,6 @@ > #include "acpi.h" > #include "asm/io.h" > > -static u32* find_resume_vector_addr(void) > -{ > - struct facs_descriptor_rev1 *facs = find_acpi_table_addr(FACS_SIGNATURE); > - if (!facs) > - return 0; > - printf("FACS is at %p\n", facs); > - return &facs->firmware_waking_vector; > -} > - > #define RTC_SECONDS_ALARM 1 > #define RTC_MINUTES_ALARM 3 > #define RTC_HOURS_ALARM 5 > @@ -40,12 +31,13 @@ extern char resume_start, resume_end; > int main(int argc, char **argv) > { > struct fadt_descriptor_rev1 *fadt = find_acpi_table_addr(FACP_SIGNATURE); > - volatile u32 *resume_vector_ptr = find_resume_vector_addr(); > + struct facs_descriptor_rev1 *facs = find_acpi_table_addr(FACS_SIGNATURE); > char *addr, *resume_vec = (void*)0x1000; > > - *resume_vector_ptr = (u32)(ulong)resume_vec; > + facs->firmware_waking_vector = (u32)(ulong)resume_vec; > > - printf("resume vector addr is %p\n", resume_vector_ptr); > + printf("FACS is at %p\n", facs); > + printf("resume vector addr is %p\n", &facs->firmware_waking_vector); > for (addr = &resume_start; addr < &resume_end; addr++) > *resume_vec++ = *addr; > printf("copy resume code from %p\n", &resume_start); > -- > 2.25.1 > Thanks, drew
Hi Drew, On 19/05/2022 14:17, Andrew Jones wrote: > On Fri, May 06, 2022 at 09:55:44PM +0100, Nikos Nikoleris wrote: >> All ACPI table definitions are provided with precise definitions of >> field sizes and offsets, make sure that no compiler optimization can >> interfere with the memory layout of the corresponding structs. > > That seems like a reasonable thing to do. I'm wondering why Linux doesn't > appear to do it. I see u-boot does, but not for all tables, which also > makes me scratch my head... I see this patch packs every struct except > rsdp_descriptor. Is there a reason it was left out? > Thanks for the review! Linux uses the following: /* * All tables must be byte-packed to match the ACPI specification, since * the tables are provided by the system BIOS. */ #pragma pack(1) ... /* Reset to default packing */ #pragma pack() Happy to switch to #pragma, if we prefer this style. I missed rsdp_descriptor, it should be packed will fix in v3. > Another comment below > >> >> Signed-off-by: Nikos Nikoleris <nikos.nikoleris@arm.com> >> --- >> lib/acpi.h | 11 ++++++++--- >> x86/s3.c | 16 ++++------------ >> 2 files changed, 12 insertions(+), 15 deletions(-) >> >> diff --git a/lib/acpi.h b/lib/acpi.h >> index 1e89840..42a2c16 100644 >> --- a/lib/acpi.h >> +++ b/lib/acpi.h >> @@ -3,6 +3,11 @@ >> >> #include "libcflat.h" >> >> +/* >> + * All tables and structures must be byte-packed to match the ACPI >> + * specification, since the tables are provided by the system BIOS >> + */ >> + >> #define ACPI_SIGNATURE(c1, c2, c3, c4) \ >> ((c1) | ((c2) << 8) | ((c3) << 16) | ((c4) << 24)) >> >> @@ -44,12 +49,12 @@ struct rsdp_descriptor { /* Root System Descriptor Pointer */ >> struct acpi_table { >> ACPI_TABLE_HEADER_DEF >> char data[0]; >> -}; >> +} __attribute__ ((packed)); >> >> struct rsdt_descriptor_rev1 { >> ACPI_TABLE_HEADER_DEF >> u32 table_offset_entry[0]; >> -}; >> +} __attribute__ ((packed)); >> >> struct fadt_descriptor_rev1 >> { >> @@ -104,7 +109,7 @@ struct facs_descriptor_rev1 >> u32 S4bios_f : 1; /* Indicates if S4BIOS support is present */ >> u32 reserved1 : 31; /* Must be 0 */ >> u8 reserved3 [40]; /* Reserved - must be zero */ >> -}; >> +} __attribute__ ((packed)); >> >> void set_efi_rsdp(struct rsdp_descriptor *rsdp); >> void* find_acpi_table_addr(u32 sig); >> diff --git a/x86/s3.c b/x86/s3.c > > The changes below in this file are unrelated, so they should be in a > separate patch. However, I'm also curious why they're needed. I see > that find_acpi_table_addr() can return NULL, so it doesn't seem like > we should be removing the check, but instead changing the check to > an assert. > These changes are necessary to appease gcc after requiring struct facs_descriptor_rev1 to be packed. >> index 378d37a..89d69fc 100644 >> --- a/x86/s3.c >> +++ b/x86/s3.c >> @@ -2,15 +2,6 @@ >> #include "acpi.h" >> #include "asm/io.h" >> >> -static u32* find_resume_vector_addr(void) >> -{ >> - struct facs_descriptor_rev1 *facs = find_acpi_table_addr(FACS_SIGNATURE); >> - if (!facs) >> - return 0; >> - printf("FACS is at %p\n", facs); >> - return &facs->firmware_waking_vector; This statement in particular results to a gcc warning. We can't get a reference to member of a packed struct. "taking address of packed member of ‘struct facs_descriptor_rev1’ may result in an unaligned pointer value" What I could do is move the x86/* changes in a separate patch in preparation of this one that packs all structs in <acpi.h> Thanks, Nikos >> -} >> - >> #define RTC_SECONDS_ALARM 1 >> #define RTC_MINUTES_ALARM 3 >> #define RTC_HOURS_ALARM 5 >> @@ -40,12 +31,13 @@ extern char resume_start, resume_end; >> int main(int argc, char **argv) >> { >> struct fadt_descriptor_rev1 *fadt = find_acpi_table_addr(FACP_SIGNATURE); >> - volatile u32 *resume_vector_ptr = find_resume_vector_addr(); >> + struct facs_descriptor_rev1 *facs = find_acpi_table_addr(FACS_SIGNATURE); >> char *addr, *resume_vec = (void*)0x1000; >> >> - *resume_vector_ptr = (u32)(ulong)resume_vec; >> + facs->firmware_waking_vector = (u32)(ulong)resume_vec; >> >> - printf("resume vector addr is %p\n", resume_vector_ptr); >> + printf("FACS is at %p\n", facs); >> + printf("resume vector addr is %p\n", &facs->firmware_waking_vector); >> for (addr = &resume_start; addr < &resume_end; addr++) >> *resume_vec++ = *addr; >> printf("copy resume code from %p\n", &resume_start); >> -- >> 2.25.1 >> > > Thanks, > drew >
On Thu, May 19, 2022 at 04:52:04PM +0100, Nikos Nikoleris wrote: > Hi Drew, > > On 19/05/2022 14:17, Andrew Jones wrote: > > On Fri, May 06, 2022 at 09:55:44PM +0100, Nikos Nikoleris wrote: > > > All ACPI table definitions are provided with precise definitions of > > > field sizes and offsets, make sure that no compiler optimization can > > > interfere with the memory layout of the corresponding structs. > > > > That seems like a reasonable thing to do. I'm wondering why Linux doesn't > > appear to do it. I see u-boot does, but not for all tables, which also > > makes me scratch my head... I see this patch packs every struct except > > rsdp_descriptor. Is there a reason it was left out? > > > > Thanks for the review! > > Linux uses the following: > > /* > * All tables must be byte-packed to match the ACPI specification, since > * the tables are provided by the system BIOS. > */ > #pragma pack(1) > > > ... > > > /* Reset to default packing */ > > #pragma pack() Ah, that makes sense. > > > Happy to switch to #pragma, if we prefer this style. > > I missed rsdp_descriptor, it should be packed will fix in v3. Maybe we should switch to the #pragma to avoid the verbosity and missing structures? (I don't have a strong opinion...) > > > > Another comment below > > > > > > > > Signed-off-by: Nikos Nikoleris <nikos.nikoleris@arm.com> > > > --- > > > lib/acpi.h | 11 ++++++++--- > > > x86/s3.c | 16 ++++------------ > > > 2 files changed, 12 insertions(+), 15 deletions(-) > > > > > > diff --git a/lib/acpi.h b/lib/acpi.h > > > index 1e89840..42a2c16 100644 > > > --- a/lib/acpi.h > > > +++ b/lib/acpi.h > > > @@ -3,6 +3,11 @@ > > > #include "libcflat.h" > > > +/* > > > + * All tables and structures must be byte-packed to match the ACPI > > > + * specification, since the tables are provided by the system BIOS > > > + */ > > > + > > > #define ACPI_SIGNATURE(c1, c2, c3, c4) \ > > > ((c1) | ((c2) << 8) | ((c3) << 16) | ((c4) << 24)) > > > @@ -44,12 +49,12 @@ struct rsdp_descriptor { /* Root System Descriptor Pointer */ > > > struct acpi_table { > > > ACPI_TABLE_HEADER_DEF > > > char data[0]; > > > -}; > > > +} __attribute__ ((packed)); > > > struct rsdt_descriptor_rev1 { > > > ACPI_TABLE_HEADER_DEF > > > u32 table_offset_entry[0]; > > > -}; > > > +} __attribute__ ((packed)); > > > struct fadt_descriptor_rev1 > > > { > > > @@ -104,7 +109,7 @@ struct facs_descriptor_rev1 > > > u32 S4bios_f : 1; /* Indicates if S4BIOS support is present */ > > > u32 reserved1 : 31; /* Must be 0 */ > > > u8 reserved3 [40]; /* Reserved - must be zero */ > > > -}; > > > +} __attribute__ ((packed)); > > > void set_efi_rsdp(struct rsdp_descriptor *rsdp); > > > void* find_acpi_table_addr(u32 sig); > > > diff --git a/x86/s3.c b/x86/s3.c > > > > The changes below in this file are unrelated, so they should be in a > > separate patch. However, I'm also curious why they're needed. I see > > that find_acpi_table_addr() can return NULL, so it doesn't seem like > > we should be removing the check, but instead changing the check to > > an assert. > > > > These changes are necessary to appease gcc after requiring struct > facs_descriptor_rev1 to be packed. > > > > index 378d37a..89d69fc 100644 > > > --- a/x86/s3.c > > > +++ b/x86/s3.c > > > @@ -2,15 +2,6 @@ > > > #include "acpi.h" > > > #include "asm/io.h" > > > -static u32* find_resume_vector_addr(void) > > > -{ > > > - struct facs_descriptor_rev1 *facs = find_acpi_table_addr(FACS_SIGNATURE); > > > - if (!facs) > > > - return 0; > > > - printf("FACS is at %p\n", facs); > > > - return &facs->firmware_waking_vector; > > This statement in particular results to a gcc warning. We can't get a > reference to member of a packed struct. > > "taking address of packed member of ‘struct facs_descriptor_rev1’ may result > in an unaligned pointer value" > > What I could do is move the x86/* changes in a separate patch in preparation > of this one that packs all structs in <acpi.h> Yes, please. Also please add an assert(facs) or 'if (!facs) exit()' to preserve that NULL check (although it doesn't look like the original code cared about the return being NULL anyway...) Thanks, drew > > Thanks, > > Nikos > > > > -} > > > - > > > #define RTC_SECONDS_ALARM 1 > > > #define RTC_MINUTES_ALARM 3 > > > #define RTC_HOURS_ALARM 5 > > > @@ -40,12 +31,13 @@ extern char resume_start, resume_end; > > > int main(int argc, char **argv) > > > { > > > struct fadt_descriptor_rev1 *fadt = find_acpi_table_addr(FACP_SIGNATURE); > > > - volatile u32 *resume_vector_ptr = find_resume_vector_addr(); > > > + struct facs_descriptor_rev1 *facs = find_acpi_table_addr(FACS_SIGNATURE); > > > char *addr, *resume_vec = (void*)0x1000; > > > - *resume_vector_ptr = (u32)(ulong)resume_vec; > > > + facs->firmware_waking_vector = (u32)(ulong)resume_vec; > > > - printf("resume vector addr is %p\n", resume_vector_ptr); > > > + printf("FACS is at %p\n", facs); > > > + printf("resume vector addr is %p\n", &facs->firmware_waking_vector); > > > for (addr = &resume_start; addr < &resume_end; addr++) > > > *resume_vec++ = *addr; > > > printf("copy resume code from %p\n", &resume_start); > > > -- > > > 2.25.1 > > > > > > > Thanks, > > drew > > >
diff --git a/lib/acpi.h b/lib/acpi.h index 1e89840..42a2c16 100644 --- a/lib/acpi.h +++ b/lib/acpi.h @@ -3,6 +3,11 @@ #include "libcflat.h" +/* + * All tables and structures must be byte-packed to match the ACPI + * specification, since the tables are provided by the system BIOS + */ + #define ACPI_SIGNATURE(c1, c2, c3, c4) \ ((c1) | ((c2) << 8) | ((c3) << 16) | ((c4) << 24)) @@ -44,12 +49,12 @@ struct rsdp_descriptor { /* Root System Descriptor Pointer */ struct acpi_table { ACPI_TABLE_HEADER_DEF char data[0]; -}; +} __attribute__ ((packed)); struct rsdt_descriptor_rev1 { ACPI_TABLE_HEADER_DEF u32 table_offset_entry[0]; -}; +} __attribute__ ((packed)); struct fadt_descriptor_rev1 { @@ -104,7 +109,7 @@ struct facs_descriptor_rev1 u32 S4bios_f : 1; /* Indicates if S4BIOS support is present */ u32 reserved1 : 31; /* Must be 0 */ u8 reserved3 [40]; /* Reserved - must be zero */ -}; +} __attribute__ ((packed)); void set_efi_rsdp(struct rsdp_descriptor *rsdp); void* find_acpi_table_addr(u32 sig); diff --git a/x86/s3.c b/x86/s3.c index 378d37a..89d69fc 100644 --- a/x86/s3.c +++ b/x86/s3.c @@ -2,15 +2,6 @@ #include "acpi.h" #include "asm/io.h" -static u32* find_resume_vector_addr(void) -{ - struct facs_descriptor_rev1 *facs = find_acpi_table_addr(FACS_SIGNATURE); - if (!facs) - return 0; - printf("FACS is at %p\n", facs); - return &facs->firmware_waking_vector; -} - #define RTC_SECONDS_ALARM 1 #define RTC_MINUTES_ALARM 3 #define RTC_HOURS_ALARM 5 @@ -40,12 +31,13 @@ extern char resume_start, resume_end; int main(int argc, char **argv) { struct fadt_descriptor_rev1 *fadt = find_acpi_table_addr(FACP_SIGNATURE); - volatile u32 *resume_vector_ptr = find_resume_vector_addr(); + struct facs_descriptor_rev1 *facs = find_acpi_table_addr(FACS_SIGNATURE); char *addr, *resume_vec = (void*)0x1000; - *resume_vector_ptr = (u32)(ulong)resume_vec; + facs->firmware_waking_vector = (u32)(ulong)resume_vec; - printf("resume vector addr is %p\n", resume_vector_ptr); + printf("FACS is at %p\n", facs); + printf("resume vector addr is %p\n", &facs->firmware_waking_vector); for (addr = &resume_start; addr < &resume_end; addr++) *resume_vec++ = *addr; printf("copy resume code from %p\n", &resume_start);
All ACPI table definitions are provided with precise definitions of field sizes and offsets, make sure that no compiler optimization can interfere with the memory layout of the corresponding structs. Signed-off-by: Nikos Nikoleris <nikos.nikoleris@arm.com> --- lib/acpi.h | 11 ++++++++--- x86/s3.c | 16 ++++------------ 2 files changed, 12 insertions(+), 15 deletions(-)