On Wed, Dec 27, 2006 at 08:23:09AM +0100, Pavel Machek wrote:
> Hey, we need testing testing testing on this patch. People were
> complaining that we don't do pci state saving, where are they now?!
Enjoying holidays?
Patched s2ram restores VGA correctly on my Lifebook S7110, but then reports:
esk# ./s2ram -f -v
Switching from vt7 to vt1
saving PCI config of device 00:02.0
restoring PCI config of device 00:02.0
switching back to vt7
*** glibc detected *** ./s2ram: corrupted double-linked list: 0x08056078
***
======= Backtrace: =========
/lib/libc.so.6[0xb7e766e1]
/lib/libc.so.6[0xb7e77b98]
/lib/libc.so.6(cfree+0x89)[0xb7e77d79]
./s2ram[0x804997f]
/lib/libc.so.6(__libc_start_main+0xdc)[0xb7e27f9c]
./s2ram[0x8049061]
======= Memory map: ========
08048000-08052000 r-xp 00000000 08:04 7065779
/usr/src/packages/BUILD/suspend
-0.5/s2ram
08052000-08053000 r--p 00009000 08:04 7065779
/usr/src/packages/BUILD/suspend
-0.5/s2ram
08053000-08055000 rw-p 0000a000 08:04 7065779
/usr/src/packages/BUILD/suspend
-0.5/s2ram
08055000-08077000 rw-p 08055000 00:00 0 [heap]
b7c00000-b7c21000 rw-p b7c00000 00:00 0
b7c21000-b7d00000 ---p b7c21000 00:00 0
b7e11000-b7e12000 rw-p b7e11000 00:00 0
b7e12000-b7f3a000 r-xp 00000000 08:04 2852882 /lib/libc-2.5.so
b7f3a000-b7f3b000 r--p 00128000 08:04 2852882 /lib/libc-2.5.so
b7f3b000-b7f3d000 rw-p 00129000 08:04 2852882 /lib/libc-2.5.so
b7f3d000-b7f40000 rw-p b7f3d000 00:00 0
b7f40000-b7f51000 r-xp 00000000 08:04 2852922 /lib/libz.so.1.2.3
b7f51000-b7f53000 rw-p 00010000 08:04 2852922 /lib/libz.so.1.2.3
b7f6a000-b7f74000 r-xp 00000000 08:04 2852927 /lib/libgcc_s.so.1
b7f74000-b7f76000 rw-p 00009000 08:04 2852927 /lib/libgcc_s.so.1
b7f76000-b7f78000 rw-p b7f76000 00:00 0
b7f78000-b7f79000 r-xp b7f78000 00:00 0 [vdso]
b7f79000-b7f94000 r-xp 00000000 08:04 2852872 /lib/ld-2.5.so
b7f94000-b7f96000 rw-p 0001a000 08:04 2852872 /lib/ld-2.5.so
bfba2000-bfbb8000 rw-p bfba2000 00:00 0 [stack]
Aborted
esk#
It's patched version from suspend-0.50-6 (rpm on OpenSuse 10.2). I have
attached patched s2ram.c too.
Best regards
Mirek Ruda
/*
* Suspend-to-RAM
*
* Copyright 2006 Pavel Machek <[EMAIL PROTECTED]>
* Distribute under GPLv2.
*/
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <errno.h>
#include <string.h>
#include <pci/pci.h>
#define S2RAM
#include "vbetool/vbetool.h"
#include "vt.h"
#include "s2ram.h"
static void *vbe_buffer;
unsigned char vga_pci_state[256];
static struct pci_dev *vga_dev = NULL;
/* Flags set from whitelist */
static int flags, vbe_mode = -1;
char bios_version[1024], sys_vendor[1024], sys_product[1024], sys_version[1024];
/* return codes for s2ram_prepare */
#define S2RAM_OK 0
#define S2RAM_FAIL 1
#define S2RAM_NOFB 126
#define S2RAM_UNKNOWN 127
/* flags for the whitelist */
#define S3_BIOS 0x01 /* machine needs acpi_sleep=s3_bios */
#define S3_MODE 0x02 /* machine needs acpi_sleep=s3_mode */
#define VBE_SAVE 0x04 /* machine needs "vbetool save / restore" */
#define VBE_POST 0x08 /* machine needs "vbetool post" */
#define RADEON_OFF 0x10 /* machine needs "radeontool light off" */
#define UNSURE 0x20 /* unverified entries from acpi-support 0.59 */
#define NOFB 0x40 /* must not use a frame buffer */
#define VBE_MODE 0x80 /* machine needs "vbetool vbemode get / set" */
#define PCI_SAVE 0x100 /* we need to save the VGA PCI registers */
#include "whitelist.c"
static void identify_machine(void)
{
printf("This machine can be identified by:\n");
printf(" sys_vendor = \"%s\"\n"
" sys_product = \"%s\"\n"
" sys_version = \"%s\"\n"
" bios_version = \"%s\"\n",
sys_vendor, sys_product, sys_version, bios_version);
printf("See http://en.opensuse.org/S2ram for details.\n"
"\n"
"If you report a problem, please include the complete output "
"above.\n");
}
void machine_known(int i)
{
if (i < 0) {
printf("Internal error: machine_known, i<0. Please report.\n");
return;
}
printf("Machine matched entry %d:\n"
" sys_vendor = '%s'\n"
" sys_product = '%s'\n"
" sys_version = '%s'\n"
" bios_version = '%s'\n", i,
whitelist[i].sys_vendor, whitelist[i].sys_product,
whitelist[i].sys_version, whitelist[i].bios_version);
printf("Fixes: 0x%x %s%s%s%s%s%s%s%s\n", flags,
(flags & VBE_SAVE) ? "VBE_SAVE " : "",
(flags & VBE_POST) ? "VBE_POST " : "",
(flags & VBE_MODE) ? "VBE_MODE " : "",
(flags & RADEON_OFF) ? "RADEON_OFF " : "",
(flags & S3_BIOS) ? "S3_BIOS " : "",
(flags & S3_MODE) ? "S3_MODE " : "",
(flags & NOFB) ? "NOFB " : "",
(flags & PCI_SAVE) ? "PCI_SAVE " : "");
if (flags & UNSURE)
printf("Machine is in the whitelist but perhaps using "
"vbetool unnecessarily.\n"
"Please try to find minimal options.\n\n");
/* in case of a bugreport we might need to find a better match than
* the one we already have (additional BIOS version e.g)...
*/
identify_machine();
}
static int set_acpi_video_mode(int mode)
{
FILE *f = fopen("/proc/sys/kernel/acpi_video_flags", "w");
if (!f) {
printf("/proc/sys/kernel/acpi_video_flags does not exist; you need a kernel >=2.6.16.\n");
return S2RAM_FAIL;
}
fprintf(f, "%d", mode);
fflush(f);
fclose(f);
return S2RAM_OK;
}
static int match(const char *t, const char *s)
{
int len = strlen(s);
/* empty string matches always */
if (len == 0)
return 1;
if (s[len-1] == '*') {
len--;
return !strncmp(t, s, len);
} else {
return !strcmp(t,s);
}
}
static int machine_match(void)
{
int i;
/* sys_vendor = NULL terminates the whitelist array */
for (i = 0; whitelist[i].sys_vendor; i++) {
if (match(sys_vendor, whitelist[i].sys_vendor) &&
match(sys_product, whitelist[i].sys_product) &&
match(sys_version, whitelist[i].sys_version) &&
match(bios_version, whitelist[i].bios_version)) {
return i;
}
}
return -1;
}
int s2ram_check(int id)
{
int ret = S2RAM_OK;
if (id < 0) {
ret = S2RAM_UNKNOWN;
} else {
flags = whitelist[id].flags;
if ((flags & NOFB) && is_framebuffer())
ret = S2RAM_NOFB;
}
return ret;
}
struct pci_dev *find_vga(void)
{
struct pci_access *pacc;
struct pci_dev *dev;
struct pci_dev *result;
pacc = pci_alloc(); /* Get the pci_access structure */
pci_init(pacc); /* Initialize the PCI library */
pci_scan_bus(pacc); /* We want to get the list of devices */
for (dev=pacc->devices; dev; dev=dev->next) {
pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_CLASS);
if (dev->device_class == 0x300)
break;
}
if (!dev)
result = NULL;
else {
/* save result */
result = malloc(sizeof(*dev));
if (result)
memcpy(result, dev, sizeof(*dev));
}
pci_cleanup(pacc);
return result;
}
void save_vga_pci(struct pci_dev *dev)
{
pci_read_block(dev, 0, vga_pci_state, 256);
}
void restore_vga_pci(struct pci_dev *dev)
{
pci_write_block(dev, 0, vga_pci_state, 256);
}
/* warning: we have to be on a text console when calling this */
int s2ram_hacks(void)
{
int ret = 0;
/* 0 means: don't touch what was set on kernel commandline */
if (flags & (S3_BIOS | S3_MODE))
ret = set_acpi_video_mode(flags & (S3_BIOS | S3_MODE));
if (ret)
return ret;
if (flags & VBE_SAVE) {
int size;
vbetool_init();
printf("Calling save_state\n");
vbe_buffer = __save_state(&size);
}
if (flags & VBE_MODE) {
vbetool_init();
printf("Calling get_mode\n");
vbe_mode = __get_mode();
}
if (flags & RADEON_OFF) {
map_radeon_cntl_mem();
printf("Calling radeon_cmd_light(0)\n");
radeon_cmd_light(0);
}
if (flags & PCI_SAVE) {
vga_dev = find_vga();
if (vga_dev) {
printf("saving PCI config of device %02x:%02x.%d\n",
vga_dev->bus, vga_dev->dev, vga_dev->func);
save_vga_pci(vga_dev);
}
}
return 0;
}
int s2ram_prepare(void)
{
int ret, id;
dmi_scan();
id = machine_match();
ret = s2ram_check(id);
if (ret)
return ret;
ret = s2ram_hacks();
return ret;
}
/* Actually enter the suspend. May be ran on frozen system. */
int s2ram_do(void)
{
int ret = 0;
FILE *f = fopen("/sys/power/state", "w");
if (!f) {
printf("/sys/power/state does not exist; what kind of ninja mutant machine is this?\n");
return ENODEV;
}
if (fprintf(f, "mem") < 0) {
ret = errno;
perror("s2ram_do");
}
/* usually only fclose fails, not fprintf, so it does not matter
* that we might overwrite the previous error.
*/
if (fclose(f) < 0) {
ret = errno;
perror("s2ram_do");
}
return ret;
}
void s2ram_resume(void)
{
if ((flags & PCI_SAVE) && vga_dev) {
printf("restoring PCI config of device %02x:%02x.%d\n",
vga_dev->bus, vga_dev->dev, vga_dev->func);
restore_vga_pci(vga_dev);
}
// FIXME: can we call vbetool_init() multiple times without cleaning up?
if (flags & VBE_POST) {
vbetool_init();
printf("Calling do_post\n");
do_post();
}
if (vbe_buffer) {
vbetool_init();
printf("Calling restore_state_from\n");
restore_state_from(vbe_buffer);
}
if (vbe_mode >= 0) {
vbetool_init();
printf("Calling set_vbe_mode\n");
set_vbe_mode(vbe_mode);
}
if (flags & RADEON_OFF) {
printf("Calling radeon_cmd_light(1)\n");
radeon_cmd_light(1);
}
}
#ifndef CONFIG_BOTH
static void usage(void)
{
printf("Usage: s2ram [-nhi] [-fspmra]\n"
"\n"
"Options:\n"
" -h, --help: this text.\n"
" -n, --test: test if the machine is in the database.\n"
" returns 0 if known and supported\n"
" -i, --identify: prints a string that identifies the machine.\n"
" -f, --force: force suspending, even on unknown machines.\n"
"\n"
"the following options are only available with --force:\n"
" -s, --vbe_save: save VBE state before suspending and "
"restore after resume.\n"
" -p, --vbe_post: VBE POST the graphics card after resume\n"
" -m, --vbe_mode: get VBE mode before suspend and set it after resume\n"
" -r, --radeontool: turn off the backlight on radeons "
"before suspending.\n"
" -a, --acpi_sleep: set the acpi_sleep parameter before "
"suspend\n"
" 1=s3_bios, 2=s3_mode, 3=both\n"
" -v, --pci_save: save the PCI config space for the VGA card.\n"
"\n");
exit(1);
}
int main(int argc, char *argv[])
{
int i, id = -1, ret = 0, test_mode = 0, force = 0;
int active_console = -1;
struct option options[] = {
{ "test", no_argument, NULL, 'n'},
{ "help", no_argument, NULL, 'h'},
{ "force", no_argument, NULL, 'f'},
{ "vbe_save", no_argument, NULL, 's'},
{ "vbe_post", no_argument, NULL, 'p'},
{ "vbe_mode", no_argument, NULL, 'm'},
{ "radeontool", no_argument, NULL, 'r'},
{ "identify", no_argument, NULL, 'i'},
{ "acpi_sleep", required_argument, NULL, 'a'},
{ "pci_save", no_argument, NULL, 'v'},
{ NULL, 0, NULL, 0 }
};
while ((i = getopt_long(argc, argv, "nhfspmriva:", options, NULL)) != -1) {
switch (i) {
case 'h':
usage();
break;
case 'i':
dmi_scan();
identify_machine();
exit(0);
case 'n':
test_mode = 1;
break;
case 'f':
force = 1;
break;
case 's':
flags |= VBE_SAVE;
break;
case 'p':
flags |= VBE_POST;
break;
case 'm':
flags |= VBE_MODE;
break;
case 'r':
flags |= RADEON_OFF;
break;
case 'a':
flags |= (atoi(optarg) & (S3_BIOS | S3_MODE));
break;
case 'v':
flags |= PCI_SAVE;
break;
default:
usage();
break;
}
}
if (flags && !force) {
printf("acpi_sleep, vbe_save, vbe_post and radeontool parameter "
"must be used with --force\n\n");
usage();
}
if (force && test_mode) {
printf("force and test mode do not make sense together.\n\n");
usage();
}
if (!force) {
dmi_scan();
id = machine_match();
ret = s2ram_check(id);
}
if (ret == S2RAM_UNKNOWN) {
printf("Machine is unknown.\n");
identify_machine();
goto out;
}
if (ret == S2RAM_NOFB)
printf("This machine can only suspend without framebuffer.\n");
if (test_mode) {
machine_known(id);
goto out;
}
if (ret)
goto out;
/* switch to console 1 first, since we might be in X */
active_console = fgconsole();
printf("Switching from vt%d to vt1\n", active_console);
chvt(1);
ret = s2ram_hacks();
if (ret)
goto out;
ret = s2ram_do();
s2ram_resume();
out:
/* if we switched consoles before suspend, switch back */
if (active_console > 0) {
printf("switching back to vt%d\n", active_console);
chvt(active_console);
}
/* and we also need to free vga_dev if allocated */
if (vga_dev)
free(vga_dev);
return ret;
}
#endif
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Suspend-devel mailing list
Suspend-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/suspend-devel