/*
 * Copyright (C) 2004-2009 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

#include <features.h>
#define __USE_FILE_OFFSET64
#define __USE_LARGEFILE64

#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

char *progname;
unsigned long addr = 0xf0000;
unsigned long size = 0x10000;


static __attribute__((__noreturn__)) void
usage(int retval)
{
	fprintf(stderr, "Usage: %s [-a addr] [-s size]\n", progname);
	exit(retval);
}

int
main(int argc, char **argv)
{
	int c;
	unsigned char bios[0x100000];
	int fd;
	int ret;


	/*
	 * Get program name.
	 */
	progname = *argv;

	/*
	 * Get options.
	 */
	while ((c = getopt(argc, argv, "a:s:")) != -1) {
		switch (c) {
		case 'a':
			addr = strtoul(optarg, (char **) 0, 0);
			break;
		case 's':
			size = strtoul(optarg, (char **) 0, 0);
			break;
		default:
			usage(1);
		}
	}
	argc -= optind;
	argv += optind;

	/*
	 * Check parameter.
	 */
	if (argc != 0) {
		usage(1);
	}
	if (sizeof(bios) < size) {
		fprintf(stderr, "Size too large (maximum: 0x%lx)!\n",
				(unsigned long) sizeof(bios));
		exit(1);
	}

	/*
	 * Do work.
	 */
	fd = open("/dev/mem", O_RDONLY | O_LARGEFILE);
	if (fd < 0) {
		fprintf(stderr, "%s: %s: open: %s.\n", progname, "/dev/mem",
				strerror(errno));
		exit(1);
	}

	ret = lseek(fd, addr, SEEK_SET);
	if (ret == -1) {
		fprintf(stderr, "%s: %s: lseek: %s.\n", progname, "/dev/mem",
				strerror(errno));
		exit(1);
	}
	if (ret != addr) {
		fprintf(stderr, "%s: %s: lseek: %s.\n", progname, "/dev/mem",
				"Bad seek");
		exit(1);
	}

	ret = read(fd, bios, size);
	if (ret < 0) {
		fprintf(stderr, "%s: %s: read: %s.\n", progname, "/dev/mem",
				strerror(errno));
		exit(1);
	}
	if (ret < size) {
		fprintf(stderr, "%s: %s: read: %s.\n", progname, "/dev/mem",
				"Short read");
		exit(1);
	}

	ret = close(fd);
	if (ret < 0) {
		fprintf(stderr, "%s: %s: close: %s.\n", progname, "/dev/mem",
				strerror(errno));
		exit(1);
	}

	ret = write(1, bios, size);
	if (ret < 0) {
		fprintf(stderr, "%s: %s: write: %s.\n", progname, "<stdout>",
				strerror(errno));
		exit(1);
	}
	if (ret < size) {
		fprintf(stderr, "%s: %s: write: %s.\n", progname, "<stdout>",
				"Short write");
		exit(1);
	}

	return 0;
}
