/*
 * ramconsole-dump.c - Dump contents of kernel ramconsole
 *
 * Copyright (C) 2009 Timo Juhani Lindfors <timo.lindfors@iki.fi>
 *  
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/mman.h>

#define RAMCONSOLE_MAGIC 0x12345678
#define RAMCONSOLE_BASE (0x30000000 + (127<<20))
#define RAMCONSOLE_SIZE (1<<20)

struct ramconsole_header {
    uint32_t magic;
    unsigned start;
    unsigned end;
    unsigned len;
    char data[1];
};

int main(int argc, char *argv[]) {
    struct ramconsole_header *ramconsole;
    int fd, i;

    fd = open("/dev/mem", O_RDONLY);
    if (fd < 0) {
        perror("/dev/mem");
        exit(1);
    }

    ramconsole = mmap(NULL,
                      RAMCONSOLE_SIZE,
                      PROT_READ,
                      MAP_SHARED,
                      fd,
                      RAMCONSOLE_BASE);
    if (ramconsole == MAP_FAILED) {
        perror("mmap");
        exit(1);
    }

    if (ramconsole->magic != RAMCONSOLE_MAGIC) {
        fprintf(stderr, "invalid magic 0x%08x\n",
                ramconsole->magic);
        exit(1);
    }

    if (sizeof(struct ramconsole_header) + ramconsole->len > RAMCONSOLE_SIZE) {
        fprintf(stderr, "ramconsole is too large (%d + %d > %d)\n",
                sizeof(struct ramconsole_header),
                ramconsole->len,
                RAMCONSOLE_SIZE);
        exit(1);
    }
    
    if (ramconsole->end - ramconsole->start > ramconsole->len) {
        /* Very theoretical issue: Kernel always updates @end first
           and only then possibly calculates new values for @start. If
           kernel dies before assigning to @start we can fix this
           safely here. */
        fprintf(stderr, "header in inconsistent state, trying to fix\n");
        ramconsole->start = ramconsole->end - ramconsole->len;
    }

    for (i = ramconsole->start; i != ramconsole->end; i++) {
        putchar(ramconsole->data[i % ramconsole->len]);
    }

    return 0;
}
