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:
Duncan Laurie 2019-03-01 15:33:47 +08:00 committed by Patrick Georgi
parent cf8094cabb
commit 48532ee3c4
1 changed files with 226 additions and 0 deletions

View File

@ -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)
}
}