vendorcode/google/chromeos: Add support for reading VPD in ACPI
This ACPI device presents an interface that allows other ACPI devices or methods to read VPD strings. The VPDF() method is provided the VPD partition to look in, and the name of the VPD key to find and it will return the VPD string if it exists. For example: VPD.VPDF ("RO", "serial_number") BUG=b:123925776 TEST=this was tested on a sarien platform by adding ACPI code that searches for a VPD key and returns the value it finds, and then setting that VPD string from the OS with the Chrome OS 'vpd' utility to ensure the ACPI method returns the correct value. Change-Id: I4668f66d7f7f364ac8c3b064d406b24135abb0f6 Signed-off-by: Duncan Laurie <dlaurie@google.com> Reviewed-on: https://review.coreboot.org/c/31668 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Lijian Zhao <lijian.zhao@intel.com>
This commit is contained in:
parent
cf8094cabb
commit
48532ee3c4
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright 2019 Google LLC
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; version 2 of
|
||||
* the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This device provides an ACPI interface to read VPD keys from either
|
||||
* the RO_VPD or RW_VPD region. For example:
|
||||
*
|
||||
* VPD.VPDF ("RO", "ro_key_name")
|
||||
* VPD.VPDF ("RW", "rw_key_name")
|
||||
*/
|
||||
|
||||
Device (VPD)
|
||||
{
|
||||
Name (_HID, "GOOG000F")
|
||||
Name (_UID, 1)
|
||||
Name (_STA, 0xf)
|
||||
|
||||
Name (VOFS, 0x600) /* Start of VPD header in VPD region */
|
||||
Name (VIHL, 0x10) /* Length of VPD info header */
|
||||
Name (VPET, 0x00) /* VPD Entry Type: Terminator */
|
||||
Name (VPES, 0x01) /* VPD Entry Type: String */
|
||||
Name (VPEI, 0xfe) /* VPD Entry Type: Info (header) */
|
||||
Name (MORE, 0x80) /* Bit to indicate more length bytes */
|
||||
|
||||
Name (VPTR, Zero) /* Pointer to current byte in VPD for parser */
|
||||
Name (VEND, Zero) /* End of VPD region */
|
||||
|
||||
/*
|
||||
* VLOC() - Return location and length of VPD region in memory.
|
||||
* These values must be initialized in GNVS by coreboot.
|
||||
*
|
||||
* Returns: Package indicating start and length of region:
|
||||
* [0] = Address of the start of VPD region.
|
||||
* [1] = Length of the VPD region.
|
||||
*/
|
||||
Method (VLOC, 1, Serialized)
|
||||
{
|
||||
Switch (ToString (Arg0))
|
||||
{
|
||||
Case ("RO") {
|
||||
Return (Package () { \ROVP, \ROVL })
|
||||
}
|
||||
Case ("RW") {
|
||||
Return (Package () { \RWVP, \RWVL })
|
||||
}
|
||||
Default {
|
||||
Return (Package () { Zero, Zero })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* VVPD() - Verify VPD info header.
|
||||
* Arg0: VPD partition base address.
|
||||
* Returns: VPD length or Zero if VPD header is not valid.
|
||||
*/
|
||||
Method (VVPD, 1, Serialized)
|
||||
{
|
||||
Local0 = Arg0 + ^VOFS
|
||||
|
||||
OperationRegion (VPDH, SystemMemory, Local0, ^VIHL)
|
||||
Field (VPDH, DWordAcc, NoLock, Preserve)
|
||||
{
|
||||
TYPE, 8, /* VPD Header Tag (=0xfe) */
|
||||
KLEN, 8, /* Key length (=9) */
|
||||
IVER, 8, /* Info version (=1) */
|
||||
SIGN, 64, /* Signature (="gVpdInfo") */
|
||||
VLEN, 8, /* Value length (=4) */
|
||||
SIZE, 32, /* VPD length */
|
||||
}
|
||||
|
||||
If (TYPE != ^VPEI) {
|
||||
Return (Zero)
|
||||
}
|
||||
If (KLEN != 9) {
|
||||
Return (Zero)
|
||||
}
|
||||
If (IVER != 1) {
|
||||
Return (Zero)
|
||||
}
|
||||
If (ToString (SIGN) != "gVpdInfo") {
|
||||
Return (Zero)
|
||||
}
|
||||
If (VLEN != 4) {
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Return (SIZE)
|
||||
}
|
||||
|
||||
/* Return next byte from VPD at pointer VPTR, and increment VPTR. */
|
||||
Method (VPRB, 0, Serialized)
|
||||
{
|
||||
If (^VPTR > ^VEND) {
|
||||
Printf ("Access beyond end of VPD region")
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Local0 = ^VPTR
|
||||
OperationRegion (VPDR, SystemMemory, Local0, One)
|
||||
Field (VPDR, DWordAcc, NoLock, Preserve)
|
||||
{
|
||||
BYTE, 8,
|
||||
}
|
||||
|
||||
/* Increment address pointer */
|
||||
^VPTR++
|
||||
Return (BYTE)
|
||||
}
|
||||
|
||||
/* Extract and return next string from VPD. */
|
||||
Method (VPDE, 0, Serialized)
|
||||
{
|
||||
Local0 = One /* Indicates if there are more bytes */
|
||||
Local1 = Zero /* Length */
|
||||
|
||||
/* Decode the string length */
|
||||
While (Local0) {
|
||||
/* Read the next byte at indicated address */
|
||||
Local2 = ^VPRB ()
|
||||
|
||||
/* Update the more bit from the byte in Local2 */
|
||||
Local0 = Local2 >> 7
|
||||
|
||||
/* Save the length bits from Local2 */
|
||||
Local1 <<= 7
|
||||
Local1 |= Local2 & 0x7f
|
||||
}
|
||||
If (!Local1) {
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
/* Extract the string */
|
||||
Local3 = Zero
|
||||
Local4 = ""
|
||||
While (Local3 < Local1) {
|
||||
Concatenate (Local4, ToString (^VPRB ()), Local4)
|
||||
Local3++
|
||||
}
|
||||
|
||||
Return (Local4)
|
||||
}
|
||||
|
||||
/*
|
||||
* VPDS() - Find next VPD key and value.
|
||||
* Returns: Package containing key and value:
|
||||
* [0] = VPD key string
|
||||
* [1] = VPD value string
|
||||
*/
|
||||
Method (VPDS, 0, Serialized)
|
||||
{
|
||||
Name (VPKV, Package () { Zero, Zero })
|
||||
|
||||
/* Read the VPD type and ensure it is a string */
|
||||
If (^VPRB () != ^VPES) {
|
||||
Printf ("VPDS: Type is not a string")
|
||||
Return (VPKV)
|
||||
}
|
||||
|
||||
/* Extract the key string and value */
|
||||
VPKV[0] = VPDE ()
|
||||
VPKV[1] = VPDE ()
|
||||
|
||||
Return (VPKV)
|
||||
}
|
||||
|
||||
/*
|
||||
* VPDF() - Find VPD key with matching name.
|
||||
* Arg0: VPD Partition, either "RO" or "RW".
|
||||
* Arg1: VPD key name to search for.
|
||||
* Returns: VPD string corresponding to VPD key, or Zero if not found.
|
||||
*/
|
||||
Method (VPDF, 2, Serialized)
|
||||
{
|
||||
Local0 = VLOC (Arg0)
|
||||
|
||||
/* Start of VPD region */
|
||||
^VPTR = DerefOf (Local0[0])
|
||||
|
||||
/* End address of VPD region */
|
||||
^VEND = ^VPTR + DerefOf (Local0[1])
|
||||
|
||||
If (!^VPTR || !^VEND) {
|
||||
Printf ("Unable to find VPD region")
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
/* Verify VPD info header and save size */
|
||||
Local0 = VVPD (^VPTR)
|
||||
If (!Local0) {
|
||||
Printf ("VPD region %o did not verify", Arg0)
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
/* Set VPD pointer to start of VPD entries */
|
||||
^VPTR += ^VOFS + ^VIHL
|
||||
|
||||
/* Search through VPD entries until key is found */
|
||||
Local1 = ""
|
||||
While (Local1 != ToString (Arg1)) {
|
||||
Local2 = VPDS ()
|
||||
Local1 = DerefOf (Local2[0])
|
||||
If (!Local1) {
|
||||
Printf ("VPD KEY %o not found", Arg1)
|
||||
Return (Zero)
|
||||
}
|
||||
}
|
||||
Local3 = DerefOf (Local2[1])
|
||||
|
||||
Printf ("Found VPD KEY %o = %o", Local1, Local3)
|
||||
Return (Local3)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue