Re: How to properly locate/parse ACPI table from kernel module?

From: Jung-uk Kim <jkim_at_FreeBSD.org>
Date: Thu, 20 May 2021 18:45:22 UTC
On 21. 5. 20., John Nielsen wrote:
>> On May 19, 2021, at 9:41 PM, John Nielsen <lists@jnielsen.net
>> <mailto:lists@jnielsen.net>> wrote:
>>
>>> On May 19, 2021, at 12:21 PM, Jung-uk Kim <jkim@freebsd.org
>>> <mailto:jkim@freebsd.org>> wrote:
>>>
>>> On 21. 5. 19., Jung-uk Kim wrote:
>>>> On 21. 5. 19., John Nielsen wrote:
>>>>>> On May 17, 2021, at 2:27 PM, Jung-uk Kim <junguk.kim@gmail.com
>>>>>> <mailto:junguk.kim@gmail.com>> wrote:
>>>>>>
>>>>>> On 21. 5. 17., John Nielsen wrote:
>>>>>>> I’m not much of a kernel programmer but I’m trying to
>>>>>>> maintain/improve the isboot module, which allows booting directly
>>>>>>> from iSCSI by reading the iSCSI Boot Firmware Table (iBFT),
>>>>>>> bringing up the interface with the details specified therein and
>>>>>>> connecting to the specified iSCSI target before trying to mount root.
>>>>>>>
>>>>>>> I’m not the original author but as the port maintainer I am
>>>>>>> hosting the code here: https://github.com/jnielsendotnet/isboot
>>>>>>> <https://github.com/jnielsendotnet/isboot>
>>>>>>>
>>>>>>> I have a test system where the module loads but fails to find the
>>>>>>> iBFT. I reviewed the iBFT code and realized it has a bunch of
>>>>>>> magic numbers mixed in with some random memory diving. If I’m
>>>>>>> reading it right (see
>>>>>>> https://github.com/jnielsendotnet/isboot/blob/master/src/ibft.h#L37
>>>>>>> <https://github.com/jnielsendotnet/isboot/blob/master/src/ibft.h#L37>
>>>>>>> and
>>>>>>> https://github.com/jnielsendotnet/isboot/blob/master/src/ibft.c#L521
>>>>>>> <https://github.com/jnielsendotnet/isboot/blob/master/src/ibft.c#L521>),
>>>>>>> it looks like it scans all of the (kernel?) memory between 512K
>>>>>>> and 1M in 16-byte increments looking for one beginning with the
>>>>>>> string “iBFT”, which if it finds will be used as the offset for
>>>>>>> reading the table. I don’t know where the 512K and 1M values came
>>>>>>> from or if they are correct, but I do have a system where that
>>>>>>> method does not work.
>>>>>>>
>>>>>>> IIUC, the iBFT is an ACPI table, and it seems like using ACPI to
>>>>>>> find it would be safer and more reliable. So my question is: how
>>>>>>> does one do that? Are there other places in the kernel code that
>>>>>>> do this sort of thing that I could use as a model? Any gotchas I
>>>>>>> should know about as a (less-than) novice kernel programmer?
>>>>>>
>>>>>> You may use AcpiGetTable() and AcpiPutTable(), e.g.,
>>>>>>
>>>>>> status = AcpiGetTable(ACPI_SIG_IBFT, …);
>>>>>
>>>>> Thank you (and Andriy) for your responses. Good to know that
>>>>> ACPI_SIG_IBFT is already defined in the upstream headers.
>>>>
>>>> It seems there are two methods.
>>>>
>>>> ftp://ftp.software.ibm.com/systems/support/bladecenter/iscsi_boot_firmware_table_v1.03.pdf
>>>> <ftp://ftp.software.ibm.com/systems/support/bladecenter/iscsi_boot_firmware_table_v1.03.pdf>
>>>>
>>>> 1.4.3.1 Locating the iBFT
>>>>
>>>> The iBFT is located by the following methods. A platform shall implement
>>>> one or more of these methods.
>>>>
>>>> 1. The ACPI Method. The iBFT is pointed to by an entry in the RSDT/XSDT.
>>>> Note that ACPI [ACPI=3.0b] specifies the string in the pointer as
>>>> “IBFT” (all upper case) HOWEVER the signature in the table being pointed
>>>> to is“iBFT” (note the mixed case).
>>>>
>>>> 2. The Low RAM Method. Scan for the table header signature in system
>>>> memory between 512K and 1024K. The scan MUST be done starting at
>>>> the lower address scanning forward to the higher address. When using the
>>>> Low RAM Method the table header must be aligned on a 16-byte
>>>> boundary.
>>>>
>>>> Note: A system operating in UEFI mode shall utilize only the ACPI
>>>> method.
>>>>
>>>> For modern system, it seems you should be using Method 1.  I don't
>>>> understand the "HOWEVER" part, though.
>>>
>>> I did little more research.  It seems iSCSI spec. predates ACPI
>>> standardization and IBM kept on using "iBFT" instead of ACPI spec.
>>> "IBFT".  Because this confusion, some systems use "iBFT" and some use
>>> "IBFT".  Therefore, it seems you need to test both, e.g.,
>>>
>>> status = AcpiGetTable(ACPI_SIG_IBFT, 0, &ibft);
>>> if (ACPI_FAILURE(status))
>>> status = AcpiGetTable("iBFT", 0, &ibft);
>>
>> Very helpful once again, thank you. My test machine (either the
>> motherboard or the NIC) has a buggy BIOS that prevents it from booting
>> in legacy mode with iSCSI so I’m using UEFI whether I wanted to or
>> not. I’m glad that my theory that the Low RAM Method might not work in
>> UEFI has some merit.
>>
>> I did notice that Linux looks for both iBFT and IBFT in its driver;
>> the existence of two standards is alluded to in the comments but it’s
>> nice to know what they are. I’ll adopt your suggested approach.
> 
> In case anyone is actually following along at home, here’s what I have
> so far:
> https://github.com/jnielsendotnet/isboot/commit/255a01102c345347dece1ed15bd8675fe3dd1dd9
> <https://github.com/jnielsendotnet/isboot/commit/255a01102c345347dece1ed15bd8675fe3dd1dd9>
> 
> Which not only compiles but also finds (and is able to correctly decode)
> the iBFT on my test system. Hooray!

Good to hear it.

> Comments on the patch welcome. Otherwise I’ll move on to the next issue…

You don't need to define USE_ACPI.  It should be spelled "DEV_ACPI", e.g.,

#ifndef DEV_ACPI

> Thank you again for the help thus far.

Glad to help.

Jung-uk Kim