tbxfroot.c 8.2 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7
/******************************************************************************
 *
 * Module Name: tbxfroot - Find the root ACPI table (RSDT)
 *
 *****************************************************************************/

/*
8
 * Copyright (C) 2000 - 2011, Intel Corp.
L
Linus Torvalds 已提交
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer,
 *    without modification.
 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
 *    substantially similar to the "NO WARRANTY" disclaimer below
 *    ("Disclaimer") and any redistribution must be conditioned upon
 *    including a substantially similar Disclaimer requirement for further
 *    binary redistribution.
 * 3. Neither the names of the above-listed copyright holders nor the names
 *    of any contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * Alternatively, this software may be distributed under the terms of the
 * GNU General Public License ("GPL") version 2 as published by the Free
 * Software Foundation.
 *
 * NO WARRANTY
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 */

#include <acpi/acpi.h>
L
Len Brown 已提交
45 46
#include "accommon.h"
#include "actables.h"
L
Linus Torvalds 已提交
47 48

#define _COMPONENT          ACPI_TABLES
L
Len Brown 已提交
49
ACPI_MODULE_NAME("tbxfroot")
L
Linus Torvalds 已提交
50

R
Robert Moore 已提交
51
/* Local prototypes */
L
Len Brown 已提交
52
static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length);
L
Linus Torvalds 已提交
53

54 55
static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp);

56 57 58 59
/*******************************************************************************
 *
 * FUNCTION:    acpi_tb_validate_rsdp
 *
60
 * PARAMETERS:  Rsdp                - Pointer to unvalidated RSDP
61 62 63 64 65 66 67
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Validate the RSDP (ptr)
 *
 ******************************************************************************/

68
static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp)
69
{
L
Len Brown 已提交
70
	ACPI_FUNCTION_ENTRY();
71 72

	/*
73 74 75 76
	 * The signature and checksum must both be correct
	 *
	 * Note: Sometimes there exists more than one RSDP in memory; the valid
	 * RSDP has a valid checksum, all others have an invalid checksum.
77
	 */
78 79
	if (ACPI_STRNCMP((char *)rsdp, ACPI_SIG_RSDP,
			 sizeof(ACPI_SIG_RSDP) - 1) != 0) {
B
Bob Moore 已提交
80

81 82 83 84 85 86 87
		/* Nope, BAD Signature */

		return (AE_BAD_SIGNATURE);
	}

	/* Check the standard checksum */

88
	if (acpi_tb_checksum((u8 *) rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) {
89 90 91 92 93 94
		return (AE_BAD_CHECKSUM);
	}

	/* Check extended checksum if table version >= 2 */

	if ((rsdp->revision >= 2) &&
95
	    (acpi_tb_checksum((u8 *) rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) {
96 97 98 99 100 101
		return (AE_BAD_CHECKSUM);
	}

	return (AE_OK);
}

L
Linus Torvalds 已提交
102 103
/*******************************************************************************
 *
104
 * FUNCTION:    acpi_find_root_pointer
L
Linus Torvalds 已提交
105
 *
106
 * PARAMETERS:  table_address           - Where the table pointer is returned
L
Linus Torvalds 已提交
107
 *
108
 * RETURN:      Status, RSDP physical address
L
Linus Torvalds 已提交
109
 *
110 111
 * DESCRIPTION: Search lower 1_mbyte of memory for the root system descriptor
 *              pointer structure.  If it is found, set *RSDP to point to it.
L
Linus Torvalds 已提交
112
 *
113 114 115
 * NOTE1:       The RSDP must be either in the first 1_k of the Extended
 *              BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.)
 *              Only a 32-bit physical address is necessary.
L
Linus Torvalds 已提交
116
 *
117 118
 * NOTE2:       This function is always available, regardless of the
 *              initialization state of the rest of ACPI.
L
Linus Torvalds 已提交
119 120 121
 *
 ******************************************************************************/

122
acpi_status acpi_find_root_pointer(acpi_size *table_address)
L
Linus Torvalds 已提交
123
{
124 125 126
	u8 *table_ptr;
	u8 *mem_rover;
	u32 physical_address;
L
Linus Torvalds 已提交
127

128
	ACPI_FUNCTION_TRACE(acpi_find_root_pointer);
L
Linus Torvalds 已提交
129

130
	/* 1a) Get the location of the Extended BIOS Data Area (EBDA) */
L
Linus Torvalds 已提交
131

132 133 134 135 136
	table_ptr = acpi_os_map_memory((acpi_physical_address)
				       ACPI_EBDA_PTR_LOCATION,
				       ACPI_EBDA_PTR_LENGTH);
	if (!table_ptr) {
		ACPI_ERROR((AE_INFO,
137
			    "Could not map memory at 0x%8.8X for length %u",
138
			    ACPI_EBDA_PTR_LOCATION, ACPI_EBDA_PTR_LENGTH));
L
Linus Torvalds 已提交
139

L
Len Brown 已提交
140
		return_ACPI_STATUS(AE_NO_MEMORY);
L
Linus Torvalds 已提交
141 142
	}

143
	ACPI_MOVE_16_TO_32(&physical_address, table_ptr);
L
Linus Torvalds 已提交
144

145
	/* Convert segment part to physical address */
L
Linus Torvalds 已提交
146

147 148
	physical_address <<= 4;
	acpi_os_unmap_memory(table_ptr, ACPI_EBDA_PTR_LENGTH);
L
Linus Torvalds 已提交
149

150
	/* EBDA present? */
L
Linus Torvalds 已提交
151

152
	if (physical_address > 0x400) {
153
		/*
154 155
		 * 1b) Search EBDA paragraphs (EBDA is required to be a
		 *     minimum of 1_k length)
156
		 */
157
		table_ptr = acpi_os_map_memory((acpi_physical_address)
158 159 160 161
					       physical_address,
					       ACPI_EBDA_WINDOW_SIZE);
		if (!table_ptr) {
			ACPI_ERROR((AE_INFO,
162
				    "Could not map memory at 0x%8.8X for length %u",
163
				    physical_address, ACPI_EBDA_WINDOW_SIZE));
L
Linus Torvalds 已提交
164

165
			return_ACPI_STATUS(AE_NO_MEMORY);
L
Linus Torvalds 已提交
166 167
		}

168 169 170 171
		mem_rover =
		    acpi_tb_scan_memory_for_rsdp(table_ptr,
						 ACPI_EBDA_WINDOW_SIZE);
		acpi_os_unmap_memory(table_ptr, ACPI_EBDA_WINDOW_SIZE);
L
Linus Torvalds 已提交
172

173
		if (mem_rover) {
B
Bob Moore 已提交
174

175
			/* Return the physical address */
L
Linus Torvalds 已提交
176

177 178
			physical_address +=
			    (u32) ACPI_PTR_DIFF(mem_rover, table_ptr);
L
Linus Torvalds 已提交
179

180 181
			*table_address = physical_address;
			return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
182 183 184
		}
	}

185 186 187 188 189 190
	/*
	 * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh
	 */
	table_ptr = acpi_os_map_memory((acpi_physical_address)
				       ACPI_HI_RSDP_WINDOW_BASE,
				       ACPI_HI_RSDP_WINDOW_SIZE);
L
Linus Torvalds 已提交
191

192 193
	if (!table_ptr) {
		ACPI_ERROR((AE_INFO,
194
			    "Could not map memory at 0x%8.8X for length %u",
195 196
			    ACPI_HI_RSDP_WINDOW_BASE,
			    ACPI_HI_RSDP_WINDOW_SIZE));
L
Linus Torvalds 已提交
197

198
		return_ACPI_STATUS(AE_NO_MEMORY);
199
	}
L
Linus Torvalds 已提交
200

201 202 203
	mem_rover =
	    acpi_tb_scan_memory_for_rsdp(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
	acpi_os_unmap_memory(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
L
Linus Torvalds 已提交
204

205
	if (mem_rover) {
L
Linus Torvalds 已提交
206

207
		/* Return the physical address */
L
Linus Torvalds 已提交
208

209 210 211
		physical_address = (u32)
		    (ACPI_HI_RSDP_WINDOW_BASE +
		     ACPI_PTR_DIFF(mem_rover, table_ptr));
L
Linus Torvalds 已提交
212

213 214
		*table_address = physical_address;
		return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
215 216
	}

217 218 219 220
	/* A valid RSDP was not found */

	ACPI_ERROR((AE_INFO, "A valid RSDP was not found"));
	return_ACPI_STATUS(AE_NOT_FOUND);
L
Linus Torvalds 已提交
221 222 223 224 225 226 227 228 229 230 231 232 233 234
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_tb_scan_memory_for_rsdp
 *
 * PARAMETERS:  start_address       - Starting pointer for search
 *              Length              - Maximum length to search
 *
 * RETURN:      Pointer to the RSDP if found, otherwise NULL.
 *
 * DESCRIPTION: Search a block of memory for the RSDP signature
 *
 ******************************************************************************/
L
Len Brown 已提交
235
static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length)
L
Linus Torvalds 已提交
236
{
L
Len Brown 已提交
237 238 239
	acpi_status status;
	u8 *mem_rover;
	u8 *end_address;
L
Linus Torvalds 已提交
240

B
Bob Moore 已提交
241
	ACPI_FUNCTION_TRACE(tb_scan_memory_for_rsdp);
L
Linus Torvalds 已提交
242 243 244 245 246 247

	end_address = start_address + length;

	/* Search from given start address for the requested length */

	for (mem_rover = start_address; mem_rover < end_address;
L
Len Brown 已提交
248
	     mem_rover += ACPI_RSDP_SCAN_STEP) {
B
Bob Moore 已提交
249

250
		/* The RSDP signature and checksum must both be correct */
L
Linus Torvalds 已提交
251

L
Len Brown 已提交
252 253
		status =
		    acpi_tb_validate_rsdp(ACPI_CAST_PTR
254
					  (struct acpi_table_rsdp, mem_rover));
L
Len Brown 已提交
255
		if (ACPI_SUCCESS(status)) {
B
Bob Moore 已提交
256

257
			/* Sig and checksum valid, we have found a real RSDP */
L
Linus Torvalds 已提交
258

L
Len Brown 已提交
259 260 261 262
			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
					  "RSDP located at physical address %p\n",
					  mem_rover));
			return_PTR(mem_rover);
L
Linus Torvalds 已提交
263 264
		}

265
		/* No sig match or bad checksum, keep searching */
L
Linus Torvalds 已提交
266 267 268 269
	}

	/* Searched entire block, no RSDP was found */

L
Len Brown 已提交
270 271 272 273
	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
			  "Searched entire block from %p, valid RSDP was not found\n",
			  start_address));
	return_PTR(NULL);
L
Linus Torvalds 已提交
274
}