Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 8 Dec 2009 07:49:55 -0500
From:      John Baldwin <jhb@freebsd.org>
To:        freebsd-acpi@freebsd.org
Cc:        Andrew Pantyukhin <infofarmer@freebsd.org>
Subject:   Re: libi386/biosacpi.c - bad RSDP checksum search
Message-ID:  <200912080749.55710.jhb@freebsd.org>
In-Reply-To: <20091208060339.GK98273@pollux.cenkes.org>
References:  <20091208060339.GK98273@pollux.cenkes.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Tuesday 08 December 2009 1:03:40 am Andrew Pantyukhin wrote:
> Our boot loader stops searching memory at the first occurrence of
> "RSD PTR" while there are BIOSes (e.g. some IBM System x) that
> have multiple such strings and the first one does not contain the
> correct checksum.
> 
> The acpi-ca code does the right thing and continues the search.
> 
> Any ACPI experts interested in fixing this? I'll be ready to
> test.

Are you sure?  It looks like it keeps going if the checksum fails.  Note the 
'continue' after the printf() about a bad checksum.

/*
 * Find the RSDP in low memory.  See section 5.2.2 of the ACPI spec.
 */
static ACPI_TABLE_RSDP *
biosacpi_find_rsdp(void)
{
    ACPI_TABLE_RSDP	*rsdp;
    uint16_t		*addr;

    /* EBDA is the 1 KB addressed by the 16 bit pointer at 0x40E. */
    addr = (uint16_t *)PTOV(0x40E);
    if ((rsdp = biosacpi_search_rsdp((char *)(*addr << 4), 0x400)) != NULL)
	return (rsdp);

    /* Check the upper memory BIOS space, 0xe0000 - 0xfffff. */
    if ((rsdp = biosacpi_search_rsdp((char *)0xe0000, 0x20000)) != NULL)
	return (rsdp);

    return (NULL);
}

static ACPI_TABLE_RSDP *
biosacpi_search_rsdp(char *base, int length)
{
    ACPI_TABLE_RSDP	*rsdp;
    u_int8_t		*cp, sum;
    int			ofs, idx;

    /* search on 16-byte boundaries */
    for (ofs = 0; ofs < length; ofs += 16) {
	rsdp = (ACPI_TABLE_RSDP *)PTOV(base + ofs);

	/* compare signature, validate checksum */
	if (!strncmp(rsdp->Signature, ACPI_SIG_RSDP, strlen(ACPI_SIG_RSDP))) {
	    cp = (u_int8_t *)rsdp;
	    sum = 0;
	    for (idx = 0; idx < RSDP_CHECKSUM_LENGTH; idx++)
		sum += *(cp + idx);
	    if (sum != 0) {
		printf("acpi: bad RSDP checksum (%d)\n", sum);
		continue;
	    }
	    return(rsdp);
	}
    }
    return(NULL);
}

-- 
John Baldwin



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200912080749.55710.jhb>