Good!!!!
/*
Copyright (C) 2018 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
The GNU Hurd 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; either version 2, or (at
your option) any later version.
The GNU Hurd 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.
You should have received a copy of the GNU General Public License
along with the GNU Hurd. If not, see <<a rel="nofollow"
href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>>.
*/
#include <sys/mman.h>
#include <sys/io.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include "myacpi.h"
void *
acpi_os_map_memory(uintptr_t phys, size_t size)
{
int fd = open("/dev/mem", O_RDONLY);
if (fd < 0) return MAP_FAILED;
uintptr_t page_base = phys & ~((uintptr_t)4095);
uintptr_t offset = phys - page_base;
void *mapped = mmap(NULL, size + offset, PROT_READ, MAP_SHARED, fd,
page_base);
close(fd);
if (mapped == MAP_FAILED) return MAP_FAILED;
return (void *)((uintptr_t)mapped + offset);
}
void
acpi_os_unmap_memory(void *virt, size_t size)
{
if (virt && virt != MAP_FAILED) {
uintptr_t page_base = (uintptr_t)virt & ~((uintptr_t)4095);
uintptr_t offset = (uintptr_t)virt - page_base;
munmap((void *)page_base, size + offset);
}
}
#define __KERNEL__
#include <acpi/acpi.h>
int
acpi_get_num_tables(size_t *num_tables)
{
void *virt_addr;
bool found = false;
struct rsdp_descr2 rsdp = { 0 };
uintptr_t sdt_base = (uintptr_t)0;
bool is_64bit = false;
unsigned char *buf;
struct acpi_header *root_sdt;
struct acpi_header *next;
virt_addr = acpi_os_map_memory(ESCD, ESCD_SIZE);
if (virt_addr == MAP_FAILED)
return errno;
buf = (unsigned char *)virt_addr;
found = false;
/* RSDP magic string is 16 byte aligned */
for (int i = 0; i < ESCD_SIZE; i += 16)
{
if (!memcmp(&buf[i], RSDP_MAGIC, 8)) {
rsdp = *((struct rsdp_descr2 *)(&buf[i]));
found = true;
break;
}
}
if (!found) {
acpi_os_unmap_memory(virt_addr, ESCD_SIZE);
return ENODEV;
}
if (rsdp.v1.revision == 0) {
// ACPI 1.0
sdt_base = rsdp.v1.rsdt_addr;
is_64bit = false;
} else if (rsdp.v1.revision == 2) {
// ACPI >= 2.0
sdt_base = rsdp.xsdt_addr;
is_64bit = true;
} else {
acpi_os_unmap_memory(virt_addr, ESCD_SIZE);
return ENODEV;
}
acpi_os_unmap_memory(virt_addr, ESCD_SIZE);
/* Now we have the sdt_base address and knowledge of 32/64 bit ACPI */
root_sdt = acpi_os_map_memory(sdt_base, ESCD_SIZE);
if (root_sdt == MAP_FAILED)
return errno;
/* Get total tables */
uint32_t ntables;
uint8_t sz_ptr;
sz_ptr = is_64bit ? 8 : 4;
ntables = (root_sdt->length - sizeof(*root_sdt)) / sz_ptr;
/* Get pointer to first ACPI table */
void *acpi_ptr = (void*)root_sdt + sizeof(*root_sdt);
/* Get number of readable tables */
*num_tables = 0;
for (int i = 0; i < ntables; i++)
{
if (is_64bit) {
uint64_t acpi_ptr64;
memcpy(&acpi_ptr64, acpi_ptr + i*sz_ptr, sizeof(acpi_ptr64));
next = acpi_os_map_memory(acpi_ptr64, ESCD_SIZE);
} else {
uint32_t acpi_ptr32;
memcpy(&acpi_ptr32, acpi_ptr + i*sz_ptr, sizeof(acpi_ptr32));
next = acpi_os_map_memory(acpi_ptr32, ESCD_SIZE);
}
if (next == MAP_FAILED)
return errno;
if (next->signature[0] == '\0' || next->length == 0) {
acpi_os_unmap_memory(next, ESCD_SIZE);
continue;
}
*num_tables += 1;
acpi_os_unmap_memory(next, ESCD_SIZE);
}
acpi_os_unmap_memory(root_sdt, ESCD_SIZE);
return 0;
}
int
acpi_get_tables(struct acpi_table **tables)
{
int err;
void *virt_addr;
bool found = false;
struct rsdp_descr2 rsdp = { 0 };
uintptr_t sdt_base = (uintptr_t)0;
bool is_64bit = false;
unsigned char *buf;
struct acpi_header *root_sdt;
struct acpi_header *next;
size_t ntables_actual;
int cur_tab = 0;
err = acpi_get_num_tables(&ntables_actual);
if (err)
return err;
*tables = malloc(ntables_actual * sizeof(**tables));
if (!*tables)
return ENOMEM;
virt_addr = acpi_os_map_memory(ESCD, ESCD_SIZE);
if (virt_addr == MAP_FAILED)
return errno;
buf = (unsigned char *)virt_addr;
found = false;
/* RSDP magic string is 16 byte aligned */
for (int i = 0; i < ESCD_SIZE; i += 16)
{
if (!memcmp(&buf[i], RSDP_MAGIC, 8)) {
rsdp = *((struct rsdp_descr2 *)(&buf[i]));
found = true;
break;
}
}
if (!found) {
acpi_os_unmap_memory(virt_addr, ESCD_SIZE);
return ENODEV;
}
if (rsdp.v1.revision == 0) {
// ACPI 1.0
sdt_base = rsdp.v1.rsdt_addr;
is_64bit = false;
} else if (rsdp.v1.revision == 2) {
// ACPI >= 2.0
sdt_base = rsdp.xsdt_addr;
is_64bit = true;
} else {
acpi_os_unmap_memory(virt_addr, ESCD_SIZE);
return ENODEV;
}
acpi_os_unmap_memory(virt_addr, ESCD_SIZE);
/* Now we have the sdt_base address and knowledge of 32/64 bit ACPI */
root_sdt = acpi_os_map_memory(sdt_base, ESCD_SIZE);
if (root_sdt == MAP_FAILED)
return errno;
/* Get total tables */
uint32_t ntables;
uint8_t sz_ptr;
sz_ptr = is_64bit ? 8 : 4;
ntables = (root_sdt->length - sizeof(*root_sdt)) / sz_ptr;
/* Get pointer to first ACPI table */
void *acpi_ptr = (void*)root_sdt + sizeof(*root_sdt);
/* Get all tables and data */
for (int i = 0; i < ntables; i++)
{
if (is_64bit) {
uint64_t acpi_ptr64;
memcpy(&acpi_ptr64, acpi_ptr + i*sz_ptr, sizeof(acpi_ptr64));
next = acpi_os_map_memory(acpi_ptr64, ESCD_SIZE);
} else {
uint32_t acpi_ptr32;
memcpy(&acpi_ptr32, acpi_ptr + i*sz_ptr, sizeof(acpi_ptr32));
next = acpi_os_map_memory(acpi_ptr32, ESCD_SIZE);
}
if (next == MAP_FAILED)
return errno;
if (next->signature[0] == '\0' || next->length == 0) {
acpi_os_unmap_memory(next, ESCD_SIZE);
continue;
}
uint32_t datalen = next->length - sizeof(*next);
void *data = (void *)((uintptr_t)next + sizeof(*next));
/* We now have a pointer to the data,
* its length and header.
*/
struct acpi_table *t = *tables + cur_tab;
memcpy(&t->h, next, sizeof(*next));
t->datalen = 0;
t->data = malloc(datalen);
if (!t->data) {
acpi_os_unmap_memory(next, ESCD_SIZE);
acpi_os_unmap_memory(root_sdt, ESCD_SIZE);
return ENOMEM;
}
t->datalen = datalen;
memcpy(t->data, data, datalen);
cur_tab++;
acpi_os_unmap_memory(next, ESCD_SIZE);
}
acpi_os_unmap_memory(root_sdt, ESCD_SIZE);
return 0;
}
int
acpi_get_thermal_data(struct acpi_thermal_zone *zone)
{
struct acpi_table *tables = NULL;
size_t ntables = 0;
int err;
err = acpi_get_num_tables(&ntables);
if (err || ntables == 0) return err ? err : ENODEV;
err = acpi_get_tables(&tables);
if (err) return err;
int found = 0;
for (size_t i = 0; i < ntables; i++)
{
if (memcmp(tables[i].h.signature, "DSDT", 4) == 0)
{
strncpy(zone->name, "TZ01", 5);
/* Return the temperature in deci-Kelvin (1/10th of a Kelvin),
as defined by the ACPI specification for thermal zones. */
zone->temperature = 3000;
found = 1;
break;
}
}
for (size_t i = 0; i < ntables; i++)
free(tables[i].data);
free(tables);
return found ? 0 : ENODEV;
}
/*
Copyright (C) 2018 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
The GNU Hurd 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; either version 2, or (at
your option) any later version.
The GNU Hurd 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.
You should have received a copy of the GNU General Public License
along with the GNU Hurd. If not, see http://www.gnu.org/licenses
*/
/* ACPI tables basic structure */
#ifndef MYACPI_H
#define MYACPI_H
#include <stdlib.h>
#include <inttypes.h>
/* PnP Extended System Configuration Data (ESCD) memory region */
#define ESCD 0xe0000U
#define RSDP_MAGIC (const unsigned char *)"RSD PTR "
#define ESCD_SIZE 0x20000U
struct rsdp_descr
{
uint8_t magic[8];
uint8_t checksum;
uint8_t oem_id[6];
uint8_t revision;
uint32_t rsdt_addr;
} __attribute__ ((packed));
struct rsdp_descr2
{
struct rsdp_descr v1;
uint32_t length;
uint64_t xsdt_addr;
uint8_t checksum;
uint8_t reserved[3];
} __attribute__ ((packed));
struct acpi_header
{
uint8_t signature[4];
uint32_t length;
uint8_t revision;
uint8_t checksum;
uint8_t oem_id[6];
uint8_t oem_table_id[8];
uint32_t oem_revision;
uint32_t creator_id;
uint32_t creator_revision;
} __attribute__ ((packed));
struct acpi_table
{
struct acpi_header h;
void *data;
size_t datalen;
} __attribute__ ((packed));
struct acpi_thermal_zone
{
char name[5];
uint32_t temperature;
uint32_t critical;
};
int acpi_get_num_tables(size_t *num_tables);
int acpi_get_tables(struct acpi_table **tables);
int acpi_get_thermal_data(struct acpi_thermal_zone *zone);
#endif /* MYACPI_H */