Beispiel #1
0
acpi_table_header_t *mon_acpi_locate_table(char *sig)
{
	acpi_table_rsdp_t *rsdp = NULL;
	void *table = NULL;

	/* Try 0x0 first for getting rsdp table */
	rsdp = scan_for_rsdp(acpi_map_memory(0), 0x400);
	if (NULL == rsdp) {
		/* Try 0xE0000 */
		MON_LOG(mask_anonymous, level_trace,
			"Try 0xE0000 for ACPI RSDP table\n");
		rsdp = scan_for_rsdp(acpi_map_memory(0xE0000), 0x1FFFF);
	}

	if (NULL == rsdp) {
		MON_LOG(mask_anonymous,
			level_error,
			"Could not find the rsdp table\n");
		return NULL;
	}

	MON_LOG(mask_anonymous, level_trace, "rsdp address %p\n", rsdp);

	/* Get the specified table from rsdp */
	table = get_acpi_table_from_rsdp(rsdp, sig);

	return table;
}
Beispiel #2
0
static struct acpi_table_header *acpi_map_table(unsigned long where, char *sig)
{
	unsigned size;
	struct acpi_table_header *tbl = (struct acpi_table_header *)
	    acpi_map_memory(where, sizeof(struct acpi_table_header));
	if (!tbl || (sig && memcmp(sig, tbl->signature, 4))) return 0;
	size = tbl->length;
	acpi_unmap_memory((u8 *) tbl, sizeof(struct acpi_table_header));
	return (struct acpi_table_header *)acpi_map_memory(where, size);
}
Beispiel #3
0
int main(int argc, char **argv)
{
	int option_index, c, fd;
	u8 *raw;
	struct acpi_rsdp_descriptor rsdpx, *x = 0;
	char *filename = 0;
	char buff[80];
	memset(select_sig, 0, 4);
	print = 1;
	connect = 0;
	addr = length = 0;
	skip = 0;
	while (1) {
		option_index = 0;
		c = getopt_long(argc, argv, "a:t:o:bl:s:h",
				    long_options, &option_index);
		if (c == -1)
			break;

		switch (c) {
		case 0:
			switch (option_index) {
			case 0:
				addr = strtoul(optarg, (char **)NULL, 16);
				break;
			case 1:
				memcpy(select_sig, optarg, 4);
				break;
			case 2:
				filename = optarg;
				break;
			case 3:
				print = 0;
				break;
			case 4:
				length = strtoul(optarg, (char **)NULL, 16);
				break;
			case 5:
				skip = strtoul(optarg, (char **)NULL, 10);
				break;
			case 6:
				usage(argv[0]);
				exit(0);
			}
			break;
		case 'a':
			addr = strtoul(optarg, (char **)NULL, 16);
			break;
		case 't':
			memcpy(select_sig, optarg, 4);
			break;
		case 'o':
			filename = optarg;
			break;
		case 'b':
			print = 0;
			break;
		case 'l':
			length = strtoul(optarg, (char **)NULL, 16);
			break;
		case 's':
			skip = strtoul(optarg, (char **)NULL, 10);
			break;
		case 'h':
			usage(argv[0]);
			exit(0);
		default:
			printf("Unknown option!\n");
			usage(argv[0]);
			exit(0);
		}
	}

	fd = STDOUT_FILENO;
	if (filename) {
		fd = creat(filename, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
		if (fd < 0)
			return fd;
	}

	if (!select_sig[0] && !print) {
		connect = 1;
	}

	psz = sysconf(_SC_PAGESIZE);
	if (length && addr) {
		/* We know length and address, it means we just want a memory dump */
		if (!(raw = acpi_map_memory(addr, length)))
			goto not_found;
		write(fd, raw, length);
		acpi_unmap_memory(raw, length);
		close(fd);
		return 0;
	}

	length = sizeof(struct acpi_rsdp_descriptor);
	if (!addr) {
		addr = read_efi_systab();
		if (!addr) {
			addr = ACPI_HI_RSDP_WINDOW_BASE;
			length = ACPI_HI_RSDP_WINDOW_SIZE;
		}
	}

	if (!(raw = acpi_map_memory(addr, length)) ||
	    !(x = acpi_scan_for_rsdp(raw, length)))
		goto not_found;

	/* Find RSDP and print all found tables */
	memcpy(&rsdpx, x, sizeof(struct acpi_rsdp_descriptor));
	acpi_unmap_memory(raw, length);
	if (connect) {
		lseek(fd, sizeof(struct acpi_rsdp_descriptor), SEEK_SET);
	}
	if (!acpi_dump_SDT(fd, &rsdpx))
		goto not_found;
	if (connect) {
		lseek(fd, 0, SEEK_SET);
		write(fd, x, (rsdpx.revision < 2) ?
			ACPI_RSDP_CHECKSUM_LENGTH : ACPI_RSDP_XCHECKSUM_LENGTH);
	} else if (!select_sig[0] || !memcmp("RSD PTR ", select_sig, 4)) {
		addr += (long)x - (long)raw;
		length = snprintf(buff, 80, "RSD PTR @ %p\n", (void *)addr);
		write(fd, buff, length);
		acpi_show_data(fd, (u8 *) & rsdpx, (rsdpx.revision < 2) ?
				ACPI_RSDP_CHECKSUM_LENGTH : ACPI_RSDP_XCHECKSUM_LENGTH);
		buff[0] = '\n';
		write(fd, buff, 1);
	}
	acpi_dump_dynamic_SSDT(fd);
	close(fd);
	return 0;
not_found:
	close(fd);
	fprintf(stderr, "ACPI tables were not found. If you know location "
		"of RSD PTR table (from dmesg, etc), "
		"supply it with either --addr or -a option\n");
	return 1;
}
Beispiel #4
0
/*
 * SLP_TYP values are programmed in PM1A and PM1B control block registers
 * to initiate power transition.  Each Sx state has a corresponding SLP_TYP
 * value. SLP_TYP values are stored in DSDT area of ACPI tables as AML packages
 * Following code searches for these packages to retreive the SLP_TYPs
 *
 * Search for '_SX_' to get to start of package.  'X' stands for sleep state
 * e.g. '_S3_'. If '_SX_' is not found then it means the system does not support
 * that sleep state.
 *
 * _SX_packages are in the following format
 *
 * 1 byte : Package Op (0x12)
 *
 * 1 byte
 * + 'Package length' size : 'Package length' field.  Refer ACPI spec for
 *                           'Package length Encoding' High 2 bits of first
 *                           byte indicates how many bytes are used by
 *                           'Package length'
 * If 0, then only the first byte is used
 *                           If > 0 then following bytes (max 3) will be also
 *                           used
 *
 * 1 byte : 'Number of Elements'
 *
 * 1 byte optional         : There may be an optional 'Byte Prefix' (0x0A)
 *                           present.
 *
 * 1 byte SLP_TYP_A : SLP_TYP value for PM1A control block
 *
 * 1 byte optional         : There may be an optional 'Byte Prefix' (0x0A)
 *                           present.
 *
 * 1 byte SLP_TYP_B : SLP_TYP value for PM1B control block
 *
 * Remaining bytes are ignored. */
void mon_acpi_retrieve_sleep_states(void)
{
	acpi_table_header_t *dsdt;
	char *aml_ptr;
	uint8_t sstate;
	uint32_t i;

	dsdt = acpi_map_memory((uint64_t)fadt.dsdt);
	if (!dsdt) {
		MON_LOG(mask_anonymous, level_error, "[ACPI] DSDT not found\n");
		return;
	}

	MON_LOG(mask_anonymous, level_trace,
		"SleepState | SleepTypeA | SleepTypeB\n");
	MON_LOG(mask_anonymous, level_trace,
		"------------------------------------\n");

	for (sstate = ACPI_STATE_S0; sstate < ACPI_S_STATE_COUNT; ++sstate) {
		aml_ptr = (char *)(dsdt + sizeof(acpi_table_header_t));

		sleep_conversion_table[ACPI_PM1_CNTRL_REG_A][sstate] = 0xff;
		sleep_conversion_table[ACPI_PM1_CNTRL_REG_B][sstate] = 0xff;

		/* Search for '_SX_' string where 'X' is the sleep state e.g. '_S3_' */
		for (i = 0; i < dsdt->length - 8; i++) {
			if (aml_ptr[0] == '_' && aml_ptr[1] == 'S'
			    && aml_ptr[2] == ('0' + sstate) && aml_ptr[3] ==
			    '_') {
				break;
			}
			aml_ptr++;
		}
		if (i < dsdt->length - 8) {
			/* Skip '_SX_' and Package Op */
			aml_ptr += 5;

			/* Skip 'Package length' bytes indicated by the 2 high bits of
			 * 'Package Lead' byte */
			aml_ptr += (*aml_ptr >> 6);

			/* Skip 'Package Lead' byte */
			aml_ptr++;

			/* Skip 'Number of Elements' byte */
			aml_ptr++;

			/* Skip 'Byte Prefix' if found */
			if (*aml_ptr == 0x0a) {
				aml_ptr++;
			}

			/* This should be SLP_TYP value for PM1A_CNT_BLK */
			sleep_conversion_table[ACPI_PM1_CNTRL_REG_A][sstate] =
				*aml_ptr;
			aml_ptr++;

			/* Skip 'Byte Prefix' if found */
			if (*aml_ptr == 0x0a) {
				aml_ptr++;
			}

			/* This should be SLP_TYP value for PM1B_CNT_BLK */
			sleep_conversion_table[ACPI_PM1_CNTRL_REG_B][sstate] =
				*aml_ptr;
		}

		MON_LOG(mask_anonymous, level_trace,
			"    %3d    |    %3d     |    %3d\n", sstate,
			sleep_conversion_table[ACPI_PM1_CNTRL_REG_A][sstate],
			sleep_conversion_table[ACPI_PM1_CNTRL_REG_B][sstate]);
	}
Beispiel #5
0
/* Find an acpi table with specified signature and return mapped address */
INLINE acpi_table_header_t *get_acpi_table_from_rsdp(acpi_table_rsdp_t *rsdp,
						     char *sig)
{
	acpi_table_header_t *sdt = NULL;
	acpi_table_header_t *tbl = NULL;
	int xsdt = 1;
	int i;
	int num;
	char *offset;

	/* Get xsdt pointer */
	if (rsdp->revision > 1 && rsdp->xsdt_physical_address) {
		MON_LOG(mask_anonymous,
			level_trace,
			"rsdp->xsdt_physical_address %lx\n",
			rsdp->xsdt_physical_address);
		sdt = acpi_map_memory(rsdp->xsdt_physical_address);
	}

	/* Or get rsdt */
	if (!sdt && rsdp->rsdt_physical_address) {
		xsdt = 0;
		MON_LOG(mask_anonymous, level_trace,
			"rsdp->rsdt_physical_address  = %x\n",
			rsdp->rsdt_physical_address);
		sdt = acpi_map_memory(rsdp->rsdt_physical_address);
	}

	/* Check if the rsdt/xsdt table pointer is NULL */
	if (NULL == sdt) {
		MON_LOG(mask_anonymous, level_error, "map rsdt/xsdt error\n");
		return NULL;
	}

	/* Make sure the table checksum is correct */
	if (checksum((unsigned char *)sdt, sdt->length)) {
		MON_LOG(mask_anonymous, level_error, "Wrong checksum in %s!\n",
			(xsdt) ? "XSDT" : "RSDT");
		return NULL;
	}

	MON_LOG(mask_anonymous, level_trace, "xsdt/rsdt checksum verified!\n");

	/* Calculate the number of table pointers in the xsdt or rsdt table */
	num = (sdt->length - sizeof(acpi_table_header_t)) /
	      ((xsdt) ? sizeof(uint64_t) : sizeof(uint32_t));

	MON_LOG(mask_anonymous, level_trace,
		"The number of table pointers in xsdt/rsdt = %d\n", num);

	/* Get to the table pointer area */
	offset = (char *)sdt + sizeof(acpi_table_header_t);

	/* Traverse the pointer list to get the desired acpi table */
	for (i = 0; i < num; ++i,
	     offset += ((xsdt) ? sizeof(uint64_t) : sizeof(uint32_t))) {
		/* Get the address from the pointer entry */
		tbl = acpi_map_memory((uint64_t)
			((xsdt) ? (*(uint64_t *)offset)
			 : (*(uint32_t *)offset)));

		/* Make sure address is valid */
		if (!tbl) {
			continue;
		}

		MON_LOG(mask_anonymous,
			level_trace,
			"Mapped ACPI table addr = %p, ",
			tbl);
		MON_LOG(mask_anonymous, level_trace, "signature = %c%c%c%c\n",
			tbl->signature[0], tbl->signature[1], tbl->signature[2],
			tbl->signature[3]);

		/* Verify table signature & table checksum */
		if ((0 == mon_memcmp(tbl->signature, sig, 4)) &&
		    !checksum((unsigned char *)tbl, tbl->length)) {
			/* Found the table with matched signature */
			MON_LOG(mask_anonymous,
				level_trace,
				"Found the table %s address = %p length = %x\n",
				sig,
				tbl,
				tbl->length);

			return tbl;
		}
	}

	MON_LOG(mask_anonymous, level_error,
		"Could not find %s table in XSDT/RSDT\n", sig);

	return NULL;
}