[LinuxBIOS] Suspend to RAM with LinuxBIOSv2

Rudolf Marek r.marek at assembler.cz
Sat Jan 5 02:11:08 CET 2008


Hi all,

I'm pleased to announce that I got S3 working with LinuxBIOSv2 on ASUS A8V-E SE
(K8 + VT8237 + K8T890)!

I'm attaching the patch which is a big mess, but perhaps all are curious how is
it done.

To be able to do S3 we must first set the register values used for sleep in ACPI
DSDT table:

+       Name (\_S3, Package () {0x01, 0x01, 0x00, 0x00 })

Plus we need some callbacks to SB code which tells LinuxBIOS if it is normal
startup or Wakeup and if it is a wakeup we need to know the vector to return to
OS. This vector is stored in one ACPI table and because LinuxBIOSv2 puts tables
on same place I will take the vector value just before I overwrite it ;)

So how it works?

LinuxBIOS will boot as usual if S3, but not executing payload but jumping to
real mode waking vector from OS. During memory initialization we need to exit
the self-refresh mode instead of training the memory again. Plus we need to
adjust the K8 registers to listen for SMAF messages from SB that we go S3.

The serious problem is that LinuxBIOS overwrites a lot of memory - lowmem,
highmem (1M above). So how to protect it for OS?

I booted linux with custom memory map 2M-1GB and LinuxBIOS had 0M-2M for its own
stuff. But If I reserved memory for linux this way, ACPI code refuses to work,
because OS waking code must be in 1MB range. I decided to patch the kernel and
put always waking code to 0xE000:0000

/linux-2.6.23.1/arch/x86_64/kernel/acpi/sleep.c

void __init acpi_reserve_bootmem(void)
{
        acpi_wakeup_address =  phys_to_virt(0xE0000);  //(unsigned
long)alloc_bootmem_low(PAGE_SIZE*2);
        printk("ACpi wakeup %x\n", acpi_wakeup_address);
        if ((&wakeup_end - &wakeup_start) > (PAGE_SIZE*2))
                printk(KERN_CRIT
                       "ACPI: Wakeup code way too big, will crash on attempt"
                       " to suspend\n");
}


Getting close to have working implementation but one thing was still missing.
The exit from Self refresh seemed not to work. But, booting with original BIOS,
rebooting to LB and then suspend/resume in LB did work! Hum something was wrong
with some chip, but not with memory itself. Today I found out. There seems to be
some undocumented bit in Winbond W83627EHF which will leave power to right parts
of the system :) The attached script fix_ehf has a workaround ;)

In the meanwhile I found out how to blink with the power LED and how to
overclock the motherboard + most GPIO meaning, so I updated the Wiki page with
that too.

So what needs to be done?

1) consolidate the memory usage of LinuxBIOSv2
2) dont clean arbitrary memory

Perhaps we could reserve last 1MB of RAM or something after 8MB of mem and put
linuxBIOS heap there when using S3 we would just reserve the region + (some
region bellow the 1MB for AP CPU boot + ACPI tables etc)

The patch has some errata update of code too, I will publish this as separate
patch - I did it because I thought I got still some memory related problem.

Unfortunately I do not have much time for this fun, very busy with other stuff,
but I needed some break ;)

Oh I forgot - the real mode switcher and A20 handler are from Linux kernel.

Thanks,

Rudolf
-------------- next part --------------
A non-text attachment was scrubbed...
Name: s3.patch
Type: text/x-patch
Size: 22908 bytes
Desc: not available
URL: <http://www.coreboot.org/pipermail/coreboot/attachments/20080105/f8b7e6b4/attachment.patch>
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: fix_ehf
URL: <http://www.coreboot.org/pipermail/coreboot/attachments/20080105/f8b7e6b4/attachment.ksh>


More information about the coreboot mailing list