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

From: John Nielsen <lists_at_jnielsen.net>
Date: Thu, 20 May 2021 03:41:56 UTC
> On May 19, 2021, at 12:21 PM, Jung-uk Kim <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> 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
>>>>> 
>>>>> 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 and 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
>> 
>> 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.

JN