blob: 2b8af6c823f29bb3c038fe431ba2ff89cf436245 [file] [log] [blame]
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fcntl.h>
#include <gflags/gflags.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/stringprintf.h"
#define PATTERN(i) ((i % 1) ? 0x55555555 : 0xAAAAAAAA)
DEFINE_bool(use_dbus, false, "Use DBus RequestSuspend (must be logged in)");
DEFINE_int64(size, 1024*1024*1024, "Amount of memory to allocate");
DEFINE_int32(wakeup_count, -1, "Value read from /sys/power/wakeup_count");
void PrintAddrMap(void *vaddr) {
int fd;
uintptr_t page = reinterpret_cast<uintptr_t>(vaddr) / getpagesize();
uint64 page_data;
fd = open("/proc/self/pagemap", O_RDONLY);
CHECK_GE(fd, 0);
CHECK_EQ(static_cast<uintptr_t>(lseek64(fd, page * 8, SEEK_SET)), page * 8);
CHECK_EQ(read(fd, &page_data, 8), 8);
printf("Vaddr: 0x%p PFN=0x%llx shift=%llu present=%lld\n", vaddr,
page_data & ((1LL << 55) - 1), (page_data & ((0x3fLL << 55))) >> 55,
(page_data & (1LL << 63)) >> 63);
}
int Suspend(void) {
if (FLAGS_use_dbus) {
return system("powerd_dbus_suspend");
} else {
return system(StringPrintf("powerd_suspend -w %d",
FLAGS_wakeup_count).c_str());
}
}
uint32* Allocate(size_t size) {
uint32 *ptr;
ptr = static_cast<uint32 *>(malloc(size));
CHECK(ptr);
return ptr;
}
void Fill(uint32 *ptr, size_t size) {
for (size_t i = 0; i < size / sizeof(*ptr); i++) {
*(ptr + i) = PATTERN(i);
}
}
bool Check(uint32 *ptr, size_t size) {
bool success = true;
for (size_t i = 0; i < size / sizeof(*ptr); i++) {
if (*(ptr + i) != PATTERN(i)) {
printf("Found changed value: Addr=%p val=0x%X, expected=0x%X\n",
ptr + i, *(ptr + i), PATTERN(i));
PrintAddrMap(ptr + i);
success = false;
}
}
return success;
}
int main(int argc, char* argv[]) {
uint32 *ptr;
google::SetUsageMessage("\n"
" Fills memory with 0x55/0xAA patterns, performs a suspend, and checks\n"
" those patterns after resume. Will return 0 on success, 1 when the\n"
" suspend operation fails, and 2 when memory errors were detected.");
google::ParseCommandLineFlags(&argc, &argv, true);
CHECK_EQ(argc, 1) << "Unexpected arguments. Try --help";
ptr = Allocate(FLAGS_size);
Fill(ptr, FLAGS_size);
if (Suspend()) {
printf("Error suspending\n");
return 1;
}
if (Check(ptr, FLAGS_size))
return 0;
// The power_MemorySuspend Autotest depends on this value.
return 2;
}