/*
 * Copyright (C) Ingo Molnar, 2002
 */
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/times.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <linux/unistd.h>

#define PAGE_SIZE 4096
#define PAGE_WORDS (PAGE_SIZE/sizeof(int))

#define CACHE_PAGES 1024
#define CACHE_SIZE (CACHE_PAGES*PAGE_SIZE)

#define WINDOW_PAGES 16
#define WINDOW_SIZE (WINDOW_PAGES*PAGE_SIZE)

#define WINDOW_START 0x48000000

static char cache_contents [CACHE_SIZE];

int main(int argc, char **argv)
{
        unsigned char *data = NULL;
        int i, j, fd, repeat = 2;
        char *ptr;

#if 1
        fd = open("/dev/shm/cache", O_RDWR|O_CREAT|O_TRUNC,S_IRWXU);
#else
        fd = open("/tmp/cache", O_RDWR|O_CREAT|O_TRUNC,S_IRWXU);
#endif

        if (fd < 0) {
                perror("death");
                printf("could not open cachefile!\n");
                exit(1);
        }

        for (i = 0; i < CACHE_PAGES; i++) {
                int *page = (int *) (cache_contents + i*PAGE_SIZE);

                for (j = 0; j < PAGE_WORDS; j++)
                        page[j] = i;
        }

        if (write(fd, cache_contents, CACHE_SIZE) != CACHE_SIZE) {
                perror("death");
                printf("could not write cachefile!\n");
                exit(1);
        }

        ptr = mmap((void *)WINDOW_START,
                        WINDOW_SIZE,
                        PROT_READ|PROT_WRITE,
                        MAP_FIXED | MAP_SHARED
//                      | MAP_POPULATE
                        , fd, 0);

        if (ptr == MAP_FAILED) {
                printf("mmap() failed, ptr = %p!\n", ptr);
                exit(1);
        }
        data = ptr;

        printf("mapping pages in reverse order via remap_file_pages():\n");

again:
        for (i = 0; i < WINDOW_PAGES; i += 2) {
                char *page = data + i*PAGE_SIZE;

                ptr = (char*)remap_file_pages(
                                page,
                                PAGE_SIZE * 2,
                                PROT_READ|PROT_WRITE,
                                (WINDOW_PAGES-i),
				0);
                if (ptr) {
                        printf("mmap() of page %d failed, ptr = %p!\n", i, ptr);
                        exit(1);
                }
        }

        printf("page contents:\n");
        for (i = 0; i < WINDOW_PAGES; i++) {
                printf(".. data[%d] (page %d): %d - ", i*PAGE_SIZE, i, data[i*PAGE_SIZE]);
                /*
                 * Double-check the correctness of the mapping:
                 */
                if (i & 1) {
                        if (data[i*PAGE_SIZE] != WINDOW_PAGES-i+2) {
                                printf("hm, mapped incorrect data!\n");
                                exit(1);
                        }
                } else {
                        if (data[i*PAGE_SIZE] != WINDOW_PAGES-i) {
                                printf("hm, mapped incorrect data!\n");
                                exit(1);
                        }
                }
                printf("OK.\n");
        }
        if (--repeat)
                goto again;

        return 0;
}
