/* * virtual page mapping and translated block handling * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #ifdef _WIN32 #include #else #include #include #endif #include #include #include #include #include #include #include #include "cpu.h" #include "exec-all.h" //#define DEBUG_TB_INVALIDATE //#define DEBUG_FLUSH //#define DEBUG_TLB /* make various TB consistency checks */ //#define DEBUG_TB_CHECK //#define DEBUG_TLB_CHECK /* threshold to flush the translated code buffer */ #define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE) #define SMC_BITMAP_USE_THRESHOLD 10 #define MMAP_AREA_START 0x00000000 #define MMAP_AREA_END 0xa8000000 TranslationBlock tbs[CODE_GEN_MAX_BLOCKS]; TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE]; TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; int nb_tbs; /* any access to the tbs or the page table must use this lock */ spinlock_t tb_lock = SPIN_LOCK_UNLOCKED; uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; uint8_t *code_gen_ptr; uint64_t phys_ram_size; int phys_ram_fd; uint8_t *phys_ram_base; uint8_t *phys_ram_dirty; typedef struct PageDesc { /* list of TBs intersecting this ram page */ TranslationBlock *first_tb; /* in order to optimize self modifying code, we count the number of lookups we do to a given page to use a bitmap */ unsigned int code_write_count; uint8_t *code_bitmap; #if defined(CONFIG_USER_ONLY) unsigned long flags; #endif } PageDesc; typedef struct PhysPageDesc { /* offset in host memory of the page + io_index in the low 12 bits */ unsigned long phys_offset; } PhysPageDesc; typedef struct VirtPageDesc { /* physical address of code page. It is valid only if 'valid_tag' matches 'virt_valid_tag' */ target_ulong phys_addr; unsigned int valid_tag; #if !defined(CONFIG_SOFTMMU) /* original page access rights. It is valid only if 'valid_tag' matches 'virt_valid_tag' */ unsigned int prot; #endif } VirtPageDesc; #define L2_BITS 10 #define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS) #define L1_SIZE (1 << L1_BITS) #define L2_SIZE (1 << L2_BITS) unsigned long qemu_real_host_page_size; unsigned long qemu_host_page_bits; unsigned long qemu_host_page_size; unsigned long qemu_host_page_mask; /* io memory support */ CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; void *io_mem_opaque[IO_MEM_NB_ENTRIES]; static int io_mem_nb = 1; /* log support */ char *logfilename = "/tmp/qemu.log"; FILE *logfile; int loglevel; void cpu_exec_init(void) { /* alloc dirty bits array */ phys_ram_dirty = qemu_malloc(phys_ram_size >> TARGET_PAGE_BITS); } /* enable or disable low levels log */ void cpu_set_log(int log_flags) { loglevel = log_flags; if (!logfile) { logfile = fopen(logfilename, "w"); if (!logfile) { perror(logfilename); _exit(1); } #if !defined(CONFIG_SOFTMMU) /* must avoid mmap() usage of glibc by setting a buffer "by hand" */ { static uint8_t logfile_buf[4096]; setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf)); } #else setvbuf(logfile, NULL, _IOLBF, 0); #endif stdout = logfile; stderr = logfile; } } void cpu_set_log_filename(const char *filename) { logfilename = strdup(filename); } /* mask must never be zero, except for A20 change call */ void cpu_interrupt(CPUState *env, int mask) { env->interrupt_request |= mask; } void cpu_reset_interrupt(CPUState *env, int mask) { env->interrupt_request &= ~mask; } CPULogItem cpu_log_items[] = { { CPU_LOG_TB_OUT_ASM, "out_asm", "show generated host assembly code for each compiled TB" }, { CPU_LOG_TB_IN_ASM, "in_asm", "show target assembly code for each compiled TB" }, { CPU_LOG_TB_OP, "op", "show micro ops for each compiled TB (only usable if 'in_asm' used)" }, #ifdef TARGET_I386 { CPU_LOG_TB_OP_OPT, "op_opt", "show micro ops after optimization for each compiled TB" }, #endif { CPU_LOG_INT, "int", "show interrupts/exceptions in short format" }, { CPU_LOG_EXEC, "exec", "show trace before each executed TB (lots of logs)" }, { CPU_LOG_TB_CPU, "cpu", "show CPU state before bloc translation" }, #ifdef TARGET_I386 { CPU_LOG_PCALL, "pcall", "show protected mode far calls/returns/exceptions" }, #endif #ifdef DEBUG_IOPORT { CPU_LOG_IOPORT, "ioport", "show all i/o ports accesses" }, #endif { 0, NULL, NULL }, }; static int cmp1(const char *s1, int n, const char *s2) { if (strlen(s2) != n) return 0; return memcmp(s1, s2, n) == 0; } /* takes a comma separated list of log masks. Return 0 if error. */ int cpu_str_to_log_mask(const char *str) { CPULogItem *item; int mask; const char *p, *p1; p = str; mask = 0; for(;;) { p1 = strchr(p, ','); if (!p1) p1 = p + strlen(p); if(cmp1(p,p1-p,"all")) { for(item = cpu_log_items; item->mask != 0; item++) { mask |= item->mask; } } else { for(item = cpu_log_items; item->mask != 0; item++) { if (cmp1(p, p1 - p, item->name)) goto found; } return 0; } found: mask |= item->mask; if (*p1 != ',') break; p = p1 + 1; } return mask; } void cpu_abort(CPUState *env, const char *fmt, ...) { va_list ap; va_start(ap, fmt); fprintf(stderr, "qemu: fatal: "); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); va_end(ap); abort(); } /* XXX: Simple implementation. Fix later */ #define MAX_MMIO 32 struct mmio_space { target_phys_addr_t start; unsigned long size; unsigned long io_index; } mmio[MAX_MMIO]; unsigned long mmio_cnt; /* register physical memory. 'size' must be a multiple of the target page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an io memory page */ void cpu_register_physical_memory(target_phys_addr_t start_addr, unsigned long size,
#!/usr/bin/perl
#
# Script for generating redboot configs, based on brcmImage.pl
#
# Copyright (C) 2015 Álvaro Fernández Rojas <noltari@gmail.com>
#
# 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.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

use strict;
use Getopt::Std;
use File::stat;

my $version = "0.1";
my %arg = (
	o => 'redboot.script',
	s => 0x1000,
	f => 0xbe430000,
	a => 0x80010000,
	l => 0x7c0000,
	t => 20,
);
my $prog = $0;
$prog =~ s/^.*\///;
getopts("r:k:o:s:f:a:l:t:vh", \%arg);

die "usage: $prog ~opts~

  -r <file>	: input rootfs file
  -k <file>	: input kernel file
  -o <file>	: output image file, default $arg{o}
  -s <size_kb>	: redboot script size, default ".sprintf('%d', parse_num($arg{s}))."
  -f <baseaddr>	: flash base, default ".sprintf('0x%x', parse_num($arg{f}))."
  -a <loadaddr>	: Kernel load address, default ".sprintf('0x%x', parse_num($arg{a}))."
  -l <linux_kb>	: linux partition size, default ".sprintf('0x%x', parse_num($arg{l}))."
  -t <timeout> 	: redboot script timeout, default ".sprintf('%d', parse_num($arg{t}))."
  -v		: be more verbose
  -h		: help, version $version

EXAMPLES:
    $prog -k kern -r rootfs
" if $arg{h} || !$arg{k} || !$arg{r};

sub parse_num
{
	my $num = @_[0];
	if (index(lc($num), lc("0x")) == 0) {
		return hex($num);
	} else {
		return $num + 0;
	}
}

sub gen_script
{
	my $kernel_off = parse_num($arg{s});
	my $kernel_addr = parse_num($arg{f});
	my $kernel_len = stat($arg{k})->size;

	my $rootfs_off = $kernel_off + $kernel_len;
	my $rootfs_addr = $kernel_addr + $kernel_len;
	my $rootfs_len = parse_num($arg{l}) - $kernel_len;
	my $rootfs_size = stat($arg{r})->size;

	my $load_addr = parse_num($arg{a});

	my $timeout = parse_num($arg{t});

	if ($arg{v}) {
		printf "kernel_off: 0x%x(%u)\n", $kernel_off, $kernel_off;
		printf "kernel_addr: 0x%x(%u)\n", $kernel_addr, $kernel_addr;
		printf "kernel_len: 0x%x(%u)\n", $kernel_len, $kernel_len;

		printf "rootfs_off: 0x%x(%u)\n", $rootfs_off, $rootfs_off;
		printf "rootfs_addr: 0x%x(%u)\n", $rootfs_addr, $rootfs_addr;
		printf "rootfs_len: 0x%x(%u)\n", $rootfs_len, $rootfs_len;
		printf "rootfs_size: 0x%x(%u)\n", $rootfs_size, $rootfs_size;
	}

	open(FO, ">$arg{o}");
	printf FO "fis init -f\n";
	printf FO "\n";
	printf FO "fconfig boot_script true\n";
	printf FO "fconfig boot_script_data\n";
	printf FO "fis load -b 0x%x -d kernel\n", $load_addr;
	printf FO "exec -c \"noinitrd\" 0x%x\n", $load_addr;
	printf FO "\n";
	printf FO "fconfig boot_script_timeout %d\n", $timeout;
	printf FO "\n";
	printf FO "fis create -o 0x%x -f 0x%x -l 0x%x kernel\n", $kernel_off, $kernel_addr, $kernel_len;
	printf FO "\n";
	printf FO "fis create -o 0x%x -s 0x%x -f 0x%x -l 0x%x rootfs\n", $rootfs_off, $rootfs_size, $rootfs_addr, $rootfs_len;
	printf FO "\n";
	printf FO "reset\n";
	close FO;
}

# MAIN
gen_script();