Following patch implements ACPI resume support for coreboot. The hardware main
hook will come in separate patch perhaps. Signed-off-by: Rudolf Marek <r.marek@assembler.cz> Acked-by: Peter Stuge <peter@stuge.se> git-svn-id: svn://svn.coreboot.org/coreboot/trunk@4101 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
This commit is contained in:
parent
497c8effce
commit
33cafe5bfb
|
@ -14,4 +14,7 @@ end
|
|||
if HAVE_ACPI_TABLES
|
||||
object acpi.o
|
||||
object acpigen.o
|
||||
if HAVE_ACPI_RESUME
|
||||
object wakeup.S
|
||||
end
|
||||
end
|
||||
|
|
|
@ -27,6 +27,11 @@
|
|||
#include <arch/acpigen.h>
|
||||
#include <device/pci.h>
|
||||
|
||||
#if HAVE_ACPI_RESUME == 1
|
||||
/* this is to be filled by SB code - startup value what was found */
|
||||
u8 acpi_slp_type;
|
||||
#endif
|
||||
|
||||
u8 acpi_checksum(u8 *table, u32 length)
|
||||
{
|
||||
u8 ret=0;
|
||||
|
@ -323,12 +328,12 @@ void acpi_create_hpet(acpi_hpet_t *hpet)
|
|||
|
||||
header->checksum = acpi_checksum((void *)hpet, sizeof(acpi_hpet_t));
|
||||
}
|
||||
|
||||
void acpi_create_facs(acpi_facs_t *facs)
|
||||
{
|
||||
|
||||
memset( (void *)facs,0, sizeof(acpi_facs_t));
|
||||
|
||||
memcpy(facs->signature,"FACS",4);
|
||||
memcpy(facs->signature, FACS_NAME, 4);
|
||||
facs->length = sizeof(acpi_facs_t);
|
||||
facs->hardware_signature = 0;
|
||||
facs->firmware_waking_vector = 0;
|
||||
|
@ -365,11 +370,114 @@ void acpi_write_rsdp(acpi_rsdp_t *rsdp, acpi_rsdt_t *rsdt)
|
|||
{
|
||||
memcpy(rsdp->signature, RSDP_SIG, 8);
|
||||
memcpy(rsdp->oem_id, OEM_ID, 6);
|
||||
|
||||
rsdp->length = sizeof(acpi_rsdp_t);
|
||||
rsdp->rsdt_address = (u32)rsdt;
|
||||
rsdp->revision = 2;
|
||||
rsdp->checksum = acpi_checksum((void *)rsdp, 20);
|
||||
rsdp->ext_checksum = acpi_checksum((void *)rsdp, sizeof(acpi_rsdp_t));
|
||||
}
|
||||
|
||||
#if HAVE_ACPI_RESUME == 1
|
||||
|
||||
int acpi_get_sleep_type(void)
|
||||
{
|
||||
return acpi_slp_type;
|
||||
}
|
||||
|
||||
int acpi_is_wakeup(void)
|
||||
{
|
||||
return (acpi_slp_type == 3);
|
||||
}
|
||||
|
||||
static acpi_rsdp_t *valid_rsdp(acpi_rsdp_t *rsdp)
|
||||
{
|
||||
if (strncmp((char *)rsdp, RSDP_SIG, sizeof(RSDP_SIG) - 1) != 0)
|
||||
return NULL;
|
||||
|
||||
printk_debug("Looking on %p for valid checksum\n", rsdp);
|
||||
|
||||
if (acpi_checksum((void *)rsdp, 20) != 0)
|
||||
return NULL;
|
||||
printk_debug("Checksum 1 passed\n");
|
||||
|
||||
if ((rsdp->revision > 1) && (acpi_checksum((void *)rsdp,
|
||||
rsdp->length) != 0))
|
||||
return NULL;
|
||||
|
||||
printk_debug("Checksum 2 passed all OK\n");
|
||||
|
||||
return rsdp;
|
||||
}
|
||||
|
||||
static acpi_rsdp_t *rsdp;
|
||||
|
||||
void *acpi_get_wakeup_rsdp(void)
|
||||
{
|
||||
return rsdp;
|
||||
}
|
||||
|
||||
void *acpi_find_wakeup_vector(void)
|
||||
{
|
||||
char *p, *end;
|
||||
|
||||
acpi_rsdt_t *rsdt;
|
||||
acpi_facs_t *facs;
|
||||
acpi_fadt_t *fadt;
|
||||
void *wake_vec;
|
||||
int i;
|
||||
|
||||
rsdp = NULL;
|
||||
|
||||
if (!acpi_is_wakeup())
|
||||
return NULL;
|
||||
|
||||
printk_debug("Trying to find the wakeup vector ...\n");
|
||||
|
||||
/* find RSDP */
|
||||
for (p = (char *) 0xe0000; p < (char *) 0xfffff; p+=16) {
|
||||
if ((rsdp = valid_rsdp((acpi_rsdp_t *) p)))
|
||||
break;
|
||||
}
|
||||
|
||||
if (rsdp == NULL)
|
||||
return NULL;
|
||||
|
||||
printk_debug("RSDP found at %p\n", rsdp);
|
||||
rsdt = (acpi_rsdt_t *) rsdp->rsdt_address;
|
||||
|
||||
end = (char *) rsdt + rsdt->header.length;
|
||||
printk_debug("RSDT found at %p ends at %p\n", rsdt, end);
|
||||
|
||||
for (i = 0; ((char *) &rsdt->entry[i]) < end; i++) {
|
||||
fadt = (acpi_fadt_t *) rsdt->entry[i];
|
||||
if (strncmp((char *)fadt, FADT_NAME, sizeof(FADT_NAME) - 1) == 0)
|
||||
break;
|
||||
fadt = NULL;
|
||||
}
|
||||
|
||||
if (fadt == NULL)
|
||||
return NULL;
|
||||
|
||||
printk_debug("FADT found at %p\n", fadt);
|
||||
facs = fadt->firmware_ctrl;
|
||||
|
||||
if (facs == NULL)
|
||||
return NULL;
|
||||
|
||||
printk_debug("FACS found at %p\n", facs);
|
||||
wake_vec = (void *) facs->firmware_waking_vector;
|
||||
printk_debug("OS waking vector is %p\n", wake_vec);
|
||||
return wake_vec;
|
||||
}
|
||||
|
||||
extern char *lowmem_backup;
|
||||
extern char *lowmem_backup_ptr;
|
||||
extern int lowmem_backup_size;
|
||||
|
||||
void acpi_jump_to_wakeup(void *vector)
|
||||
{
|
||||
/* just restore the SMP trampoline and continue with wakeup on assembly level */
|
||||
memcpy(lowmem_backup_ptr, lowmem_backup, lowmem_backup_size);
|
||||
acpi_jmp_to_realm_wakeup((u32) vector);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2009 Rudolf Marek <r.marek@assembler.cz>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License v2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
.text
|
||||
.code32
|
||||
.globl acpi_jmp_to_realm_wakeup
|
||||
/* This function does the PM -> RM switch, but
|
||||
it can run >1MB even in real mode */
|
||||
|
||||
acpi_jmp_to_realm_wakeup:
|
||||
mov 0x4(%esp), %eax
|
||||
/* last 4 bits of linear addr are taken as offset */
|
||||
andw $0x0f, %ax
|
||||
movw %ax, (jmp_off)
|
||||
mov 0x4(%esp), %eax
|
||||
/* the rest is taken as segment */
|
||||
shr $4, %eax
|
||||
movw %ax, (jmp_seg)
|
||||
lgdt gdtaddr_wakeup
|
||||
movl $0x008,%eax
|
||||
mov %eax,%ds
|
||||
movl %eax,%es
|
||||
movl %eax,%ss
|
||||
movl %eax,%fs
|
||||
movl %eax,%gs
|
||||
ljmp $0x0010,$reload_cs
|
||||
.code16gcc
|
||||
reload_cs:
|
||||
/* switch off PE */
|
||||
movl %cr0, %eax
|
||||
andb $0xfe,%al
|
||||
movl %eax, %cr0
|
||||
movw $0x0, %ax
|
||||
movw %ax, %ds
|
||||
movw %ax, %es
|
||||
movw %ax, %ss
|
||||
movw %ax, %fs
|
||||
movw %ax, %gs
|
||||
/* far jump to OS waking vector. The linear addr is changed to SEG and OFFSET
|
||||
check ACPI specs or above code for details */
|
||||
.byte 0xea
|
||||
jmp_off:
|
||||
.word 0
|
||||
jmp_seg:
|
||||
.word 0
|
||||
|
||||
.code32
|
||||
gdt_wakeup_limit = gdt_wakeup_end - gdt_wakeup - 1 /* compute the table limit */
|
||||
gdtaddr_wakeup:
|
||||
.word gdt_wakeup_limit /* the table limit */
|
||||
.long gdt_wakeup /* we know the offset */
|
||||
|
||||
.data
|
||||
|
||||
/* This is the gdt for GCC part of coreboot.
|
||||
* It is different from the gdt in ROMCC/ASM part of coreboot
|
||||
* which is defined in entry32.inc */
|
||||
gdt_wakeup:
|
||||
/* selgdt 0, unused */
|
||||
.word 0x0000, 0x0000 /* dummy */
|
||||
.byte 0x00, 0x00, 0x00, 0x00
|
||||
|
||||
/* selgdt 8, flat data segment 16bit */
|
||||
.word 0x0000, 0x0000 /* dummy */
|
||||
.byte 0x00, 0x93, 0x8f, 0x00 /* G=1 and 0x0f, So we get 4Gbytes for limit */
|
||||
|
||||
/* selgdt 0x10, flat code segment 16bit */
|
||||
.word 0xffff, 0x0000
|
||||
.byte 0x00, 0x9b, 0x8f, 0x00 /* G=1 and 0x0f, So we get 4Gbytes for limit */
|
||||
|
||||
gdt_wakeup_end:
|
||||
|
||||
.previous
|
||||
.code32
|
|
@ -17,6 +17,9 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
/* 0 = S0, 1 = S1 ...*/
|
||||
extern u8 acpi_slp_type;
|
||||
|
||||
#define RSDP_SIG "RSD PTR " /* RSDT Pointer signature */
|
||||
#define RSDP_NAME "RSDP"
|
||||
|
||||
|
@ -27,6 +30,8 @@
|
|||
#define SRAT_NAME "SRAT"
|
||||
#define SLIT_NAME "SLIT"
|
||||
#define SSDT_NAME "SSDT"
|
||||
#define FACS_NAME "FACS"
|
||||
#define FADT_NAME "FACP"
|
||||
|
||||
#define RSDT_TABLE "RSDT "
|
||||
#define HPET_TABLE "AMD64 "
|
||||
|
@ -328,6 +333,10 @@ void acpi_create_facs(acpi_facs_t *facs);
|
|||
|
||||
void acpi_write_rsdt(acpi_rsdt_t *rsdt);
|
||||
void acpi_write_rsdp(acpi_rsdp_t *rsdp, acpi_rsdt_t *rsdt);
|
||||
void *acpi_find_wakeup_vector(void);
|
||||
void *acpi_get_wakeup_rsdp(void);
|
||||
extern void acpi_jmp_to_realm_wakeup(u32 linear_addr);
|
||||
void acpi_jump_to_wakeup(void *wakeup_addr);
|
||||
|
||||
unsigned long acpi_add_ssdt_pstates(acpi_rsdt_t *rsdt, unsigned long current);
|
||||
|
||||
|
|
Loading…
Reference in New Issue