Add acpi poweroff
Use acpi poweroff if it's possible. Change-Id: I103cc288523bf63fa536750b1d408ac88bbe35fb Signed-off-by: Ben Gras <ben@minix3.org> Signed-off-by: Tomas Hruby <tom@minix3.org>
This commit is contained in:
parent
4fb3945025
commit
26428d4bc6
3 changed files with 189 additions and 0 deletions
|
@ -12,6 +12,20 @@ struct acpi_rsdp acpi_rsdp;
|
||||||
static acpi_read_t read_func;
|
static acpi_read_t read_func;
|
||||||
|
|
||||||
#define MAX_RSDT 35 /* ACPI defines 35 signatures */
|
#define MAX_RSDT 35 /* ACPI defines 35 signatures */
|
||||||
|
#define SLP_EN_CODE (1 << 13) /* ACPI SLP_EN_CODE code */
|
||||||
|
#define AMI_PACKAGE_OP_CODE (0x12)
|
||||||
|
#define AMI_NAME_OP_CODE (0x8)
|
||||||
|
#define AMI_BYTE_PREFIX_CODE (0xA)
|
||||||
|
#define AMI_PACKAGE_LENGTH_ENCODING_BITS_MASK (0xC0)
|
||||||
|
#define AMI_PACKAGE_LENGTH_ENCODING_BITS_SHIFT (6)
|
||||||
|
#define AMI_MIN_PACKAGE_LENGTH (1)
|
||||||
|
#define AMI_NUM_ELEMENTS_LENGTH (1)
|
||||||
|
#define AMI_SLP_TYPA_SHIFT (10)
|
||||||
|
#define AMI_SLP_TYPB_SHIFT (10)
|
||||||
|
#define AMI_S5_NAME_OP_OFFSET_1 (-1)
|
||||||
|
#define AMI_S5_NAME_OP_OFFSET_2 (-2)
|
||||||
|
#define AMI_S5_PACKAGE_OP_OFFSET (4)
|
||||||
|
#define AMI_S5_PACKET_LENGTH_OFFSET (5)
|
||||||
|
|
||||||
static struct acpi_rsdt {
|
static struct acpi_rsdt {
|
||||||
struct acpi_sdt_header hdr;
|
struct acpi_sdt_header hdr;
|
||||||
|
@ -24,6 +38,10 @@ static struct {
|
||||||
} sdt_trans[MAX_RSDT];
|
} sdt_trans[MAX_RSDT];
|
||||||
|
|
||||||
static int sdt_count;
|
static int sdt_count;
|
||||||
|
static u16_t pm1a_cnt_blk = 0;
|
||||||
|
static u16_t pm1b_cnt_blk = 0;
|
||||||
|
static u16_t slp_typa = 0;
|
||||||
|
static u16_t slp_typb = 0;
|
||||||
|
|
||||||
static int acpi_check_csum(struct acpi_sdt_header * tb, size_t size)
|
static int acpi_check_csum(struct acpi_sdt_header * tb, size_t size)
|
||||||
{
|
{
|
||||||
|
@ -210,6 +228,86 @@ static int get_acpi_rsdp(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void acpi_init_poweroff(void)
|
||||||
|
{
|
||||||
|
u8_t *ptr = NULL;
|
||||||
|
u8_t *start = NULL;
|
||||||
|
u8_t *end = NULL;
|
||||||
|
struct acpi_fadt_header *fadt_header = NULL;
|
||||||
|
struct acpi_rsdt * dsdt_header = NULL;
|
||||||
|
char *msg = NULL;
|
||||||
|
|
||||||
|
/* Everything used here existed since ACPI spec 1.0 */
|
||||||
|
/* So we can safely use them */
|
||||||
|
fadt_header = (struct acpi_fadt_header *)
|
||||||
|
acpi_phys2vir(acpi_get_table_base("FACP"));
|
||||||
|
if (fadt_header == NULL) {
|
||||||
|
msg = "Could not load FACP";
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
dsdt_header = (struct acpi_rsdt *)
|
||||||
|
acpi_phys2vir((phys_bytes) fadt_header->dsdt);
|
||||||
|
if (dsdt_header == NULL) {
|
||||||
|
msg = "Could not load DSDT";
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
pm1a_cnt_blk = fadt_header->pm1a_cnt_blk;
|
||||||
|
pm1b_cnt_blk = fadt_header->pm1b_cnt_blk;
|
||||||
|
|
||||||
|
ptr = start = (u8_t *) dsdt_header->data;
|
||||||
|
end = start + dsdt_header->hdr.length - 4;
|
||||||
|
|
||||||
|
/* See http://forum.osdev.org/viewtopic.php?t=16990 */
|
||||||
|
/* for layout of \_S5 */
|
||||||
|
while (ptr < end && memcmp(ptr, "_S5_", 4) != 0)
|
||||||
|
ptr++;
|
||||||
|
|
||||||
|
msg = "Could not read S5 data. Use default SLP_TYPa and SLP_TYPb";
|
||||||
|
if (ptr >= end || ptr == start)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
/* validate AML structure */
|
||||||
|
if (*(ptr + AMI_S5_PACKAGE_OP_OFFSET) != AMI_PACKAGE_OP_CODE)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
if ((ptr < start + (-AMI_S5_NAME_OP_OFFSET_2) ||
|
||||||
|
(*(ptr + AMI_S5_NAME_OP_OFFSET_2) != AMI_NAME_OP_CODE ||
|
||||||
|
*(ptr + AMI_S5_NAME_OP_OFFSET_2 + 1) != '\\')) &&
|
||||||
|
*(ptr + AMI_S5_NAME_OP_OFFSET_1) != AMI_NAME_OP_CODE)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
ptr += AMI_S5_PACKET_LENGTH_OFFSET;
|
||||||
|
if (ptr >= end)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
/* package length */
|
||||||
|
ptr += ((*ptr & AMI_PACKAGE_LENGTH_ENCODING_BITS_MASK) >>
|
||||||
|
AMI_PACKAGE_LENGTH_ENCODING_BITS_SHIFT) +
|
||||||
|
AMI_MIN_PACKAGE_LENGTH + AMI_NUM_ELEMENTS_LENGTH;
|
||||||
|
if (ptr >= end)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
if (*ptr == AMI_BYTE_PREFIX_CODE)
|
||||||
|
ptr++; /* skip byte prefix */
|
||||||
|
|
||||||
|
slp_typa = (*ptr) << AMI_SLP_TYPA_SHIFT;
|
||||||
|
|
||||||
|
ptr++; /* move to SLP_TYPb */
|
||||||
|
if (*ptr == AMI_BYTE_PREFIX_CODE)
|
||||||
|
ptr++; /* skip byte prefix */
|
||||||
|
|
||||||
|
slp_typb = (*ptr) << AMI_SLP_TYPB_SHIFT;
|
||||||
|
|
||||||
|
msg = "poweroff initialized";
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if (msg) {
|
||||||
|
printf("acpi: %s\n", msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void acpi_init(void)
|
void acpi_init(void)
|
||||||
{
|
{
|
||||||
int s, i;
|
int s, i;
|
||||||
|
@ -239,6 +337,8 @@ void acpi_init(void)
|
||||||
sdt_trans[i].signature[ACPI_SDT_SIGNATURE_LEN] = '\0';
|
sdt_trans[i].signature[ACPI_SDT_SIGNATURE_LEN] = '\0';
|
||||||
sdt_trans[i].length = hdr.length;
|
sdt_trans[i].length = hdr.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
acpi_init_poweroff();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct acpi_madt_ioapic * acpi_get_ioapic_next(void)
|
struct acpi_madt_ioapic * acpi_get_ioapic_next(void)
|
||||||
|
@ -293,3 +393,19 @@ struct acpi_madt_lapic * acpi_get_lapic_next(void)
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void __k_unpaged_acpi_poweroff(void)
|
||||||
|
{
|
||||||
|
/* NO OP poweroff symbol*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void acpi_poweroff(void)
|
||||||
|
{
|
||||||
|
if (pm1a_cnt_blk == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
outw(pm1a_cnt_blk, slp_typa | SLP_EN_CODE);
|
||||||
|
if (pm1b_cnt_blk != 0) {
|
||||||
|
outw(pm1b_cnt_blk, slp_typb | SLP_EN_CODE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -30,6 +30,70 @@ struct acpi_sdt_header {
|
||||||
u32_t creator_revision;
|
u32_t creator_revision;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct acpi_generic_address {
|
||||||
|
u8_t address_space_id;
|
||||||
|
u8_t register_bit_width;
|
||||||
|
u8_t register_bit_offset;
|
||||||
|
u8_t access_size;
|
||||||
|
u64_t address;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct acpi_fadt_header
|
||||||
|
{
|
||||||
|
struct acpi_sdt_header hdr;
|
||||||
|
u32_t facs;
|
||||||
|
u32_t dsdt;
|
||||||
|
u8_t model;
|
||||||
|
u8_t preferred_pm_profile;
|
||||||
|
u16_t sci_int;
|
||||||
|
u32_t smi_cmd;
|
||||||
|
u8_t acpi_enable;
|
||||||
|
u8_t acpi_disable;
|
||||||
|
u8_t s4bios_req;
|
||||||
|
u8_t pstate_cnt;
|
||||||
|
u32_t pm1a_evt_blk;
|
||||||
|
u32_t pm1b_evt_blk;
|
||||||
|
u32_t pm1a_cnt_blk;
|
||||||
|
u32_t pm1b_cnt_blk;
|
||||||
|
u32_t pm2_cnt_blk;
|
||||||
|
u32_t pm_tmr_blk;
|
||||||
|
u32_t gpe0_blk;
|
||||||
|
u32_t gpe1_blk;
|
||||||
|
u8_t pm1_evt_len;
|
||||||
|
u8_t pm1_cnt_len;
|
||||||
|
u8_t pm2_cnt_len;
|
||||||
|
u8_t pm_tmr_len;
|
||||||
|
u8_t gpe0_blk_len;
|
||||||
|
u8_t gpe1_blk_len;
|
||||||
|
u8_t gpe1_base;
|
||||||
|
u8_t cst_cnt;
|
||||||
|
u16_t p_lvl2_lat;
|
||||||
|
u16_t p_lvl3_lat;
|
||||||
|
u16_t flush_size;
|
||||||
|
u16_t flush_stride;
|
||||||
|
u8_t duty_offset;
|
||||||
|
u8_t duty_width;
|
||||||
|
u8_t day_alrm;
|
||||||
|
u8_t mon_alrm;
|
||||||
|
u8_t century;
|
||||||
|
u16_t iapc_boot_arch;
|
||||||
|
u8_t reserved1;
|
||||||
|
u32_t flags;
|
||||||
|
struct acpi_generic_address reset_reg;
|
||||||
|
u8_t reset_value;
|
||||||
|
u8_t reserved2[3];
|
||||||
|
u64_t xfacs;
|
||||||
|
u64_t xdsdt;
|
||||||
|
struct acpi_generic_address xpm1a_evt_blk;
|
||||||
|
struct acpi_generic_address xpm1b_evt_blk;
|
||||||
|
struct acpi_generic_address xpm1a_cnt_blk;
|
||||||
|
struct acpi_generic_address xpm1b_cnt_blk;
|
||||||
|
struct acpi_generic_address xpm2_cnt_blk;
|
||||||
|
struct acpi_generic_address xpm_tmr_blk;
|
||||||
|
struct acpi_generic_address xgpe0_blk;
|
||||||
|
struct acpi_generic_address xgpe1_blk;
|
||||||
|
};
|
||||||
|
|
||||||
struct acpi_madt_hdr {
|
struct acpi_madt_hdr {
|
||||||
struct acpi_sdt_header hdr;
|
struct acpi_sdt_header hdr;
|
||||||
u32_t local_apic_address;
|
u32_t local_apic_address;
|
||||||
|
@ -84,6 +148,8 @@ struct acpi_madt_nmi {
|
||||||
|
|
||||||
void acpi_init(void);
|
void acpi_init(void);
|
||||||
|
|
||||||
|
void acpi_poweroff(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns a pointer to the io acpi structure in the MADT table in ACPI. The
|
* Returns a pointer to the io acpi structure in the MADT table in ACPI. The
|
||||||
* pointer is valid only until paging is turned off. No memory is allocated in
|
* pointer is valid only until paging is turned off. No memory is allocated in
|
||||||
|
|
|
@ -22,6 +22,10 @@
|
||||||
#include "direct_utils.h"
|
#include "direct_utils.h"
|
||||||
#include <machine/multiboot.h>
|
#include <machine/multiboot.h>
|
||||||
|
|
||||||
|
#ifdef USE_ACPI
|
||||||
|
#include "acpi.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define KBCMDP 4 /* kbd controller port (O) */
|
#define KBCMDP 4 /* kbd controller port (O) */
|
||||||
#define KBC_PULSE0 0xfe /* pulse output bit 0 */
|
#define KBC_PULSE0 0xfe /* pulse output bit 0 */
|
||||||
#define IO_KBD 0x060 /* 8042 Keyboard */
|
#define IO_KBD 0x060 /* 8042 Keyboard */
|
||||||
|
@ -85,6 +89,9 @@ poweroff(void)
|
||||||
{
|
{
|
||||||
const char *shutdown_str;
|
const char *shutdown_str;
|
||||||
|
|
||||||
|
#ifdef USE_ACPI
|
||||||
|
acpi_poweroff();
|
||||||
|
#endif
|
||||||
/* Bochs/QEMU poweroff */
|
/* Bochs/QEMU poweroff */
|
||||||
shutdown_str = "Shutdown";
|
shutdown_str = "Shutdown";
|
||||||
while (*shutdown_str) outb(0x8900, *(shutdown_str++));
|
while (*shutdown_str) outb(0x8900, *(shutdown_str++));
|
||||||
|
|
Loading…
Reference in a new issue