mirror of https://gitee.com/openkylin/qemu.git
sparc64 marge (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1462 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
8979b2277d
commit
3475187dd8
|
@ -4,6 +4,7 @@ version 0.7.1:
|
|||
- Windows 2000 install disk full hack (original idea from Vladimir
|
||||
N. Oleynik)
|
||||
- VMDK disk image creation (Filip Navara)
|
||||
- SPARC64 progress (Blue Swirl)
|
||||
|
||||
version 0.7.0:
|
||||
|
||||
|
|
|
@ -349,7 +349,11 @@ VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o
|
|||
VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o
|
||||
endif
|
||||
ifeq ($(TARGET_BASE_ARCH), sparc)
|
||||
VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t08.o magic-load.o slavio_intctl.o slavio_timer.o slavio_serial.o fdc.o esp.o
|
||||
ifeq ($(TARGET_ARCH), sparc64)
|
||||
VL_OBJS+= sun4u.o m48t08.o magic-load.o slavio_serial.o
|
||||
else
|
||||
VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t08.o magic-load.o slavio_intctl.o slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o
|
||||
endif
|
||||
endif
|
||||
ifdef CONFIG_GDBSTUB
|
||||
VL_OBJS+=gdbstub.o
|
||||
|
@ -442,7 +446,8 @@ op.o: op.c op_template.h
|
|||
endif
|
||||
|
||||
ifeq ($(TARGET_BASE_ARCH), sparc)
|
||||
op.o: op.c op_template.h op_mem.h
|
||||
op.o: op.c op_template.h op_mem.h fop_template.h fbranch_template.h
|
||||
magic_load.o: elf_op.h
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH), ppc)
|
||||
|
|
34
cpu-exec.c
34
cpu-exec.c
|
@ -47,6 +47,9 @@ void cpu_loop_exit(void)
|
|||
longjmp(env->jmp_env, 1);
|
||||
}
|
||||
#endif
|
||||
#ifndef TARGET_SPARC
|
||||
#define reg_T2
|
||||
#endif
|
||||
|
||||
/* exit the current TB from a signal handler. The host registers are
|
||||
restored in a state compatible with the CPU emulator
|
||||
|
@ -74,8 +77,12 @@ void cpu_resume_from_signal(CPUState *env1, void *puc)
|
|||
|
||||
int cpu_exec(CPUState *env1)
|
||||
{
|
||||
int saved_T0, saved_T1, saved_T2;
|
||||
int saved_T0, saved_T1;
|
||||
#if defined(reg_T2)
|
||||
int saved_T2;
|
||||
#endif
|
||||
CPUState *saved_env;
|
||||
#if defined(TARGET_I386)
|
||||
#ifdef reg_EAX
|
||||
int saved_EAX;
|
||||
#endif
|
||||
|
@ -100,6 +107,11 @@ int cpu_exec(CPUState *env1)
|
|||
#ifdef reg_EDI
|
||||
int saved_EDI;
|
||||
#endif
|
||||
#elif defined(TARGET_SPARC)
|
||||
#if defined(reg_REGWPTR)
|
||||
uint32_t *saved_regwptr;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef __sparc__
|
||||
int saved_i7, tmp_T0;
|
||||
#endif
|
||||
|
@ -115,7 +127,9 @@ int cpu_exec(CPUState *env1)
|
|||
env = env1;
|
||||
saved_T0 = T0;
|
||||
saved_T1 = T1;
|
||||
#if defined(reg_T2)
|
||||
saved_T2 = T2;
|
||||
#endif
|
||||
#ifdef __sparc__
|
||||
/* we also save i7 because longjmp may not restore it */
|
||||
asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
|
||||
|
@ -164,6 +178,9 @@ int cpu_exec(CPUState *env1)
|
|||
env->cpsr = psr & ~CACHED_CPSR_BITS;
|
||||
}
|
||||
#elif defined(TARGET_SPARC)
|
||||
#if defined(reg_REGWPTR)
|
||||
saved_regwptr = REGWPTR;
|
||||
#endif
|
||||
#elif defined(TARGET_PPC)
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
|
@ -354,7 +371,9 @@ int cpu_exec(CPUState *env1)
|
|||
cpu_dump_state(env, logfile, fprintf, 0);
|
||||
env->cpsr &= ~CACHED_CPSR_BITS;
|
||||
#elif defined(TARGET_SPARC)
|
||||
cpu_dump_state (env, logfile, fprintf, 0);
|
||||
REGWPTR = env->regbase + (env->cwp * 16);
|
||||
env->regwptr = REGWPTR;
|
||||
cpu_dump_state(env, logfile, fprintf, 0);
|
||||
#elif defined(TARGET_PPC)
|
||||
cpu_dump_state(env, logfile, fprintf, 0);
|
||||
#else
|
||||
|
@ -376,7 +395,11 @@ int cpu_exec(CPUState *env1)
|
|||
cs_base = 0;
|
||||
pc = env->regs[15];
|
||||
#elif defined(TARGET_SPARC)
|
||||
flags = 0;
|
||||
#ifdef TARGET_SPARC64
|
||||
flags = (env->pstate << 2) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
|
||||
#else
|
||||
flags = env->psrs | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1);
|
||||
#endif
|
||||
cs_base = env->npc;
|
||||
pc = env->pc;
|
||||
#elif defined(TARGET_PPC)
|
||||
|
@ -657,6 +680,9 @@ int cpu_exec(CPUState *env1)
|
|||
env->cpsr = compute_cpsr();
|
||||
/* XXX: Save/restore host fpu exception state?. */
|
||||
#elif defined(TARGET_SPARC)
|
||||
#if defined(reg_REGWPTR)
|
||||
REGWPTR = saved_regwptr;
|
||||
#endif
|
||||
#elif defined(TARGET_PPC)
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
|
@ -666,7 +692,9 @@ int cpu_exec(CPUState *env1)
|
|||
#endif
|
||||
T0 = saved_T0;
|
||||
T1 = saved_T1;
|
||||
#if defined(reg_T2)
|
||||
T2 = saved_T2;
|
||||
#endif
|
||||
env = saved_env;
|
||||
return ret;
|
||||
}
|
||||
|
|
3
disas.c
3
disas.c
|
@ -155,6 +155,9 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
|
|||
print_insn = print_insn_arm;
|
||||
#elif defined(TARGET_SPARC)
|
||||
print_insn = print_insn_sparc;
|
||||
#ifdef TARGET_SPARC64
|
||||
disasm_info.mach = bfd_mach_sparc_v9b;
|
||||
#endif
|
||||
#elif defined(TARGET_PPC)
|
||||
if (cpu_single_env->msr[MSR_LE])
|
||||
disasm_info.endian = BFD_ENDIAN_LITTLE;
|
||||
|
|
47
gdbstub.c
47
gdbstub.c
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* gdb server stub
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -293,7 +293,7 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
|||
#elif defined (TARGET_SPARC)
|
||||
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
||||
{
|
||||
uint32_t *registers = (uint32_t *)mem_buf, tmp;
|
||||
target_ulong *registers = (target_ulong *)mem_buf;
|
||||
int i;
|
||||
|
||||
/* fill in g0..g7 */
|
||||
|
@ -308,10 +308,15 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
|||
for (i = 0; i < 32; i++) {
|
||||
registers[i + 32] = tswapl(*((uint32_t *)&env->fpr[i]));
|
||||
}
|
||||
#ifndef TARGET_SPARC64
|
||||
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
|
||||
registers[64] = tswapl(env->y);
|
||||
tmp = GET_PSR(env);
|
||||
registers[65] = tswapl(tmp);
|
||||
{
|
||||
target_ulong tmp;
|
||||
|
||||
tmp = GET_PSR(env);
|
||||
registers[65] = tswapl(tmp);
|
||||
}
|
||||
registers[66] = tswapl(env->wim);
|
||||
registers[67] = tswapl(env->tbr);
|
||||
registers[68] = tswapl(env->pc);
|
||||
|
@ -319,13 +324,24 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
|||
registers[70] = tswapl(env->fsr);
|
||||
registers[71] = 0; /* csr */
|
||||
registers[72] = 0;
|
||||
|
||||
return 73 * 4;
|
||||
return 73 * sizeof(target_ulong);
|
||||
#else
|
||||
for (i = 0; i < 32; i += 2) {
|
||||
registers[i/2 + 64] = tswapl(*((uint64_t *)&env->fpr[i]));
|
||||
}
|
||||
registers[81] = tswapl(env->pc);
|
||||
registers[82] = tswapl(env->npc);
|
||||
registers[83] = tswapl(env->tstate[env->tl]);
|
||||
registers[84] = tswapl(env->fsr);
|
||||
registers[85] = tswapl(env->fprs);
|
||||
registers[86] = tswapl(env->y);
|
||||
return 87 * sizeof(target_ulong);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
||||
{
|
||||
uint32_t *registers = (uint32_t *)mem_buf;
|
||||
target_ulong *registers = (target_ulong *)mem_buf;
|
||||
int i;
|
||||
|
||||
/* fill in g0..g7 */
|
||||
|
@ -334,12 +350,13 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
|||
}
|
||||
/* fill in register window */
|
||||
for(i = 0; i < 24; i++) {
|
||||
env->regwptr[i] = tswapl(registers[i]);
|
||||
env->regwptr[i] = tswapl(registers[i + 8]);
|
||||
}
|
||||
/* fill in fprs */
|
||||
for (i = 0; i < 32; i++) {
|
||||
*((uint32_t *)&env->fpr[i]) = tswapl(registers[i + 32]);
|
||||
}
|
||||
#ifndef TARGET_SPARC64
|
||||
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
|
||||
env->y = tswapl(registers[64]);
|
||||
PUT_PSR(env, tswapl(registers[65]));
|
||||
|
@ -348,6 +365,20 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
|||
env->pc = tswapl(registers[68]);
|
||||
env->npc = tswapl(registers[69]);
|
||||
env->fsr = tswapl(registers[70]);
|
||||
#else
|
||||
for (i = 0; i < 32; i += 2) {
|
||||
uint64_t tmp;
|
||||
tmp = tswapl(registers[i/2 + 64]) << 32;
|
||||
tmp |= tswapl(registers[i/2 + 64 + 1]);
|
||||
*((uint64_t *)&env->fpr[i]) = tmp;
|
||||
}
|
||||
env->pc = tswapl(registers[81]);
|
||||
env->npc = tswapl(registers[82]);
|
||||
env->tstate[env->tl] = tswapl(registers[83]);
|
||||
env->fsr = tswapl(registers[84]);
|
||||
env->fprs = tswapl(registers[85]);
|
||||
env->y = tswapl(registers[86]);
|
||||
#endif
|
||||
}
|
||||
#elif defined (TARGET_ARM)
|
||||
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
||||
|
|
|
@ -0,0 +1,218 @@
|
|||
#ifdef BSWAP_NEEDED
|
||||
static void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr)
|
||||
{
|
||||
bswap16s(&ehdr->e_type); /* Object file type */
|
||||
bswap16s(&ehdr->e_machine); /* Architecture */
|
||||
bswap32s(&ehdr->e_version); /* Object file version */
|
||||
bswapSZs(&ehdr->e_entry); /* Entry point virtual address */
|
||||
bswapSZs(&ehdr->e_phoff); /* Program header table file offset */
|
||||
bswapSZs(&ehdr->e_shoff); /* Section header table file offset */
|
||||
bswap32s(&ehdr->e_flags); /* Processor-specific flags */
|
||||
bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */
|
||||
bswap16s(&ehdr->e_phentsize); /* Program header table entry size */
|
||||
bswap16s(&ehdr->e_phnum); /* Program header table entry count */
|
||||
bswap16s(&ehdr->e_shentsize); /* Section header table entry size */
|
||||
bswap16s(&ehdr->e_shnum); /* Section header table entry count */
|
||||
bswap16s(&ehdr->e_shstrndx); /* Section header string table index */
|
||||
}
|
||||
|
||||
static void glue(bswap_phdr, SZ)(struct elf_phdr *phdr)
|
||||
{
|
||||
bswap32s(&phdr->p_type); /* Segment type */
|
||||
bswapSZs(&phdr->p_offset); /* Segment file offset */
|
||||
bswapSZs(&phdr->p_vaddr); /* Segment virtual address */
|
||||
bswapSZs(&phdr->p_paddr); /* Segment physical address */
|
||||
bswapSZs(&phdr->p_filesz); /* Segment size in file */
|
||||
bswapSZs(&phdr->p_memsz); /* Segment size in memory */
|
||||
bswap32s(&phdr->p_flags); /* Segment flags */
|
||||
bswapSZs(&phdr->p_align); /* Segment alignment */
|
||||
}
|
||||
|
||||
static void glue(bswap_shdr, SZ)(struct elf_shdr *shdr)
|
||||
{
|
||||
bswap32s(&shdr->sh_name);
|
||||
bswap32s(&shdr->sh_type);
|
||||
bswapSZs(&shdr->sh_flags);
|
||||
bswapSZs(&shdr->sh_addr);
|
||||
bswapSZs(&shdr->sh_offset);
|
||||
bswapSZs(&shdr->sh_size);
|
||||
bswap32s(&shdr->sh_link);
|
||||
bswap32s(&shdr->sh_info);
|
||||
bswapSZs(&shdr->sh_addralign);
|
||||
bswapSZs(&shdr->sh_entsize);
|
||||
}
|
||||
|
||||
static void glue(bswap_sym, SZ)(struct elf_sym *sym)
|
||||
{
|
||||
bswap32s(&sym->st_name);
|
||||
bswapSZs(&sym->st_value);
|
||||
bswapSZs(&sym->st_size);
|
||||
bswap16s(&sym->st_shndx);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int glue(find_phdr, SZ)(struct elfhdr *ehdr, int fd, struct elf_phdr *phdr, elf_word type)
|
||||
{
|
||||
int i, retval;
|
||||
|
||||
retval = lseek(fd, ehdr->e_phoff, SEEK_SET);
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < ehdr->e_phnum; i++) {
|
||||
retval = read(fd, phdr, sizeof(*phdr));
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
glue(bswap_phdr, SZ)(phdr);
|
||||
if (phdr->p_type == type)
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void * glue(find_shdr, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, elf_word type)
|
||||
{
|
||||
int i, retval;
|
||||
|
||||
retval = lseek(fd, ehdr->e_shoff, SEEK_SET);
|
||||
if (retval < 0)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < ehdr->e_shnum; i++) {
|
||||
retval = read(fd, shdr, sizeof(*shdr));
|
||||
if (retval < 0)
|
||||
return NULL;
|
||||
glue(bswap_shdr, SZ)(shdr);
|
||||
if (shdr->sh_type == type)
|
||||
return qemu_malloc(shdr->sh_size);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void * glue(find_strtab, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET);
|
||||
if (retval < 0)
|
||||
return NULL;
|
||||
|
||||
retval = read(fd, shdr, sizeof(*shdr));
|
||||
if (retval < 0)
|
||||
return NULL;
|
||||
glue(bswap_shdr, SZ)(shdr);
|
||||
if (shdr->sh_type == SHT_STRTAB)
|
||||
return qemu_malloc(shdr->sh_size);;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int glue(read_program, SZ)(int fd, struct elf_phdr *phdr, void *dst, elf_word entry)
|
||||
{
|
||||
int retval;
|
||||
retval = lseek(fd, phdr->p_offset + entry - phdr->p_vaddr, SEEK_SET);
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
return read(fd, dst, phdr->p_filesz);
|
||||
}
|
||||
|
||||
static int glue(read_section, SZ)(int fd, struct elf_shdr *s, void *dst)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = lseek(fd, s->sh_offset, SEEK_SET);
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
retval = read(fd, dst, s->sh_size);
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void * glue(process_section, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, elf_word type)
|
||||
{
|
||||
void *dst;
|
||||
|
||||
dst = glue(find_shdr, SZ)(ehdr, fd, shdr, type);
|
||||
if (!dst)
|
||||
goto error;
|
||||
|
||||
if (glue(read_section, SZ)(fd, shdr, dst))
|
||||
goto error;
|
||||
return dst;
|
||||
error:
|
||||
qemu_free(dst);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void * glue(process_strtab, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
|
||||
{
|
||||
void *dst;
|
||||
|
||||
dst = glue(find_strtab, SZ)(ehdr, fd, shdr, symtab);
|
||||
if (!dst)
|
||||
goto error;
|
||||
|
||||
if (glue(read_section, SZ)(fd, shdr, dst))
|
||||
goto error;
|
||||
return dst;
|
||||
error:
|
||||
qemu_free(dst);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd)
|
||||
{
|
||||
struct elf_shdr symtab, strtab;
|
||||
struct elf_sym *syms;
|
||||
#if (SZ == 64)
|
||||
struct elf32_sym *syms32;
|
||||
#endif
|
||||
struct syminfo *s;
|
||||
int nsyms, i;
|
||||
char *str;
|
||||
|
||||
/* Symbol table */
|
||||
syms = glue(process_section, SZ)(ehdr, fd, &symtab, SHT_SYMTAB);
|
||||
if (!syms)
|
||||
return;
|
||||
|
||||
nsyms = symtab.sh_size / sizeof(struct elf_sym);
|
||||
#if (SZ == 64)
|
||||
syms32 = qemu_mallocz(nsyms * sizeof(struct elf32_sym));
|
||||
#endif
|
||||
for (i = 0; i < nsyms; i++) {
|
||||
glue(bswap_sym, SZ)(&syms[i]);
|
||||
#if (SZ == 64)
|
||||
syms32[i].st_name = syms[i].st_name;
|
||||
syms32[i].st_info = syms[i].st_info;
|
||||
syms32[i].st_other = syms[i].st_other;
|
||||
syms32[i].st_shndx = syms[i].st_shndx;
|
||||
syms32[i].st_value = syms[i].st_value & 0xffffffff;
|
||||
syms32[i].st_size = syms[i].st_size & 0xffffffff;
|
||||
#endif
|
||||
}
|
||||
/* String table */
|
||||
str = glue(process_strtab, SZ)(ehdr, fd, &strtab, &symtab);
|
||||
if (!str)
|
||||
goto error_freesyms;
|
||||
|
||||
/* Commit */
|
||||
s = qemu_mallocz(sizeof(*s));
|
||||
#if (SZ == 64)
|
||||
s->disas_symtab = syms32;
|
||||
qemu_free(syms);
|
||||
#else
|
||||
s->disas_symtab = syms;
|
||||
#endif
|
||||
s->disas_num_syms = nsyms;
|
||||
s->disas_strtab = str;
|
||||
s->next = syminfos;
|
||||
syminfos = s;
|
||||
return;
|
||||
error_freesyms:
|
||||
#if (SZ == 64)
|
||||
qemu_free(syms32);
|
||||
#endif
|
||||
qemu_free(syms);
|
||||
return;
|
||||
}
|
280
hw/magic-load.c
280
hw/magic-load.c
|
@ -56,213 +56,49 @@ static void bswap_ahdr(struct exec *e)
|
|||
|
||||
#include "elf.h"
|
||||
|
||||
#ifdef BSWAP_NEEDED
|
||||
static void bswap_ehdr(Elf32_Ehdr *ehdr)
|
||||
{
|
||||
bswap16s(&ehdr->e_type); /* Object file type */
|
||||
bswap16s(&ehdr->e_machine); /* Architecture */
|
||||
bswap32s(&ehdr->e_version); /* Object file version */
|
||||
bswap32s(&ehdr->e_entry); /* Entry point virtual address */
|
||||
bswap32s(&ehdr->e_phoff); /* Program header table file offset */
|
||||
bswap32s(&ehdr->e_shoff); /* Section header table file offset */
|
||||
bswap32s(&ehdr->e_flags); /* Processor-specific flags */
|
||||
bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */
|
||||
bswap16s(&ehdr->e_phentsize); /* Program header table entry size */
|
||||
bswap16s(&ehdr->e_phnum); /* Program header table entry count */
|
||||
bswap16s(&ehdr->e_shentsize); /* Section header table entry size */
|
||||
bswap16s(&ehdr->e_shnum); /* Section header table entry count */
|
||||
bswap16s(&ehdr->e_shstrndx); /* Section header string table index */
|
||||
}
|
||||
|
||||
static void bswap_phdr(Elf32_Phdr *phdr)
|
||||
{
|
||||
bswap32s(&phdr->p_type); /* Segment type */
|
||||
bswap32s(&phdr->p_offset); /* Segment file offset */
|
||||
bswap32s(&phdr->p_vaddr); /* Segment virtual address */
|
||||
bswap32s(&phdr->p_paddr); /* Segment physical address */
|
||||
bswap32s(&phdr->p_filesz); /* Segment size in file */
|
||||
bswap32s(&phdr->p_memsz); /* Segment size in memory */
|
||||
bswap32s(&phdr->p_flags); /* Segment flags */
|
||||
bswap32s(&phdr->p_align); /* Segment alignment */
|
||||
}
|
||||
|
||||
static void bswap_shdr(Elf32_Shdr *shdr)
|
||||
{
|
||||
bswap32s(&shdr->sh_name);
|
||||
bswap32s(&shdr->sh_type);
|
||||
bswap32s(&shdr->sh_flags);
|
||||
bswap32s(&shdr->sh_addr);
|
||||
bswap32s(&shdr->sh_offset);
|
||||
bswap32s(&shdr->sh_size);
|
||||
bswap32s(&shdr->sh_link);
|
||||
bswap32s(&shdr->sh_info);
|
||||
bswap32s(&shdr->sh_addralign);
|
||||
bswap32s(&shdr->sh_entsize);
|
||||
}
|
||||
|
||||
static void bswap_sym(Elf32_Sym *sym)
|
||||
{
|
||||
bswap32s(&sym->st_name);
|
||||
bswap32s(&sym->st_value);
|
||||
bswap32s(&sym->st_size);
|
||||
bswap16s(&sym->st_shndx);
|
||||
}
|
||||
#else
|
||||
#define bswap_ehdr(e) do { } while (0)
|
||||
#define bswap_phdr(e) do { } while (0)
|
||||
#define bswap_shdr(e) do { } while (0)
|
||||
#define bswap_sym(e) do { } while (0)
|
||||
#ifndef BSWAP_NEEDED
|
||||
#define bswap_ehdr32(e) do { } while (0)
|
||||
#define bswap_phdr32(e) do { } while (0)
|
||||
#define bswap_shdr32(e) do { } while (0)
|
||||
#define bswap_sym32(e) do { } while (0)
|
||||
#ifdef TARGET_SPARC64
|
||||
#define bswap_ehdr64(e) do { } while (0)
|
||||
#define bswap_phdr64(e) do { } while (0)
|
||||
#define bswap_shdr64(e) do { } while (0)
|
||||
#define bswap_sym64(e) do { } while (0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static int find_phdr(struct elfhdr *ehdr, int fd, struct elf_phdr *phdr, uint32_t type)
|
||||
{
|
||||
int i, retval;
|
||||
#define SZ 32
|
||||
#define elf_word uint32_t
|
||||
#define bswapSZs bswap32s
|
||||
#include "elf_ops.h"
|
||||
|
||||
retval = lseek(fd, ehdr->e_phoff, SEEK_SET);
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < ehdr->e_phnum; i++) {
|
||||
retval = read(fd, phdr, sizeof(*phdr));
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
bswap_phdr(phdr);
|
||||
if (phdr->p_type == type)
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void *find_shdr(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, uint32_t type)
|
||||
{
|
||||
int i, retval;
|
||||
|
||||
retval = lseek(fd, ehdr->e_shoff, SEEK_SET);
|
||||
if (retval < 0)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < ehdr->e_shnum; i++) {
|
||||
retval = read(fd, shdr, sizeof(*shdr));
|
||||
if (retval < 0)
|
||||
return NULL;
|
||||
bswap_shdr(shdr);
|
||||
if (shdr->sh_type == type)
|
||||
return qemu_malloc(shdr->sh_size);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET);
|
||||
if (retval < 0)
|
||||
return NULL;
|
||||
|
||||
retval = read(fd, shdr, sizeof(*shdr));
|
||||
if (retval < 0)
|
||||
return NULL;
|
||||
bswap_shdr(shdr);
|
||||
if (shdr->sh_type == SHT_STRTAB)
|
||||
return qemu_malloc(shdr->sh_size);;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int read_program(int fd, struct elf_phdr *phdr, void *dst, uint32_t entry)
|
||||
{
|
||||
int retval;
|
||||
retval = lseek(fd, phdr->p_offset + entry - phdr->p_vaddr, SEEK_SET);
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
return read(fd, dst, phdr->p_filesz);
|
||||
}
|
||||
|
||||
static int read_section(int fd, struct elf_shdr *s, void *dst)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = lseek(fd, s->sh_offset, SEEK_SET);
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
retval = read(fd, dst, s->sh_size);
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *process_section(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, uint32_t type)
|
||||
{
|
||||
void *dst;
|
||||
|
||||
dst = find_shdr(ehdr, fd, shdr, type);
|
||||
if (!dst)
|
||||
goto error;
|
||||
|
||||
if (read_section(fd, shdr, dst))
|
||||
goto error;
|
||||
return dst;
|
||||
error:
|
||||
qemu_free(dst);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *process_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
|
||||
{
|
||||
void *dst;
|
||||
|
||||
dst = find_strtab(ehdr, fd, shdr, symtab);
|
||||
if (!dst)
|
||||
goto error;
|
||||
|
||||
if (read_section(fd, shdr, dst))
|
||||
goto error;
|
||||
return dst;
|
||||
error:
|
||||
qemu_free(dst);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void load_symbols(struct elfhdr *ehdr, int fd)
|
||||
{
|
||||
struct elf_shdr symtab, strtab;
|
||||
struct elf_sym *syms;
|
||||
struct syminfo *s;
|
||||
int nsyms, i;
|
||||
char *str;
|
||||
|
||||
/* Symbol table */
|
||||
syms = process_section(ehdr, fd, &symtab, SHT_SYMTAB);
|
||||
if (!syms)
|
||||
return;
|
||||
|
||||
nsyms = symtab.sh_size / sizeof(struct elf_sym);
|
||||
for (i = 0; i < nsyms; i++)
|
||||
bswap_sym(&syms[i]);
|
||||
|
||||
/* String table */
|
||||
str = process_strtab(ehdr, fd, &strtab, &symtab);
|
||||
if (!str)
|
||||
goto error_freesyms;
|
||||
|
||||
/* Commit */
|
||||
s = qemu_mallocz(sizeof(*s));
|
||||
s->disas_symtab = syms;
|
||||
s->disas_num_syms = nsyms;
|
||||
s->disas_strtab = str;
|
||||
s->next = syminfos;
|
||||
syminfos = s;
|
||||
return;
|
||||
error_freesyms:
|
||||
qemu_free(syms);
|
||||
return;
|
||||
}
|
||||
#ifdef TARGET_SPARC64
|
||||
#undef elfhdr
|
||||
#undef elf_phdr
|
||||
#undef elf_shdr
|
||||
#undef elf_sym
|
||||
#undef elf_note
|
||||
#undef elf_word
|
||||
#undef bswapSZs
|
||||
#undef SZ
|
||||
#define elfhdr elf64_hdr
|
||||
#define elf_phdr elf64_phdr
|
||||
#define elf_note elf64_note
|
||||
#define elf_shdr elf64_shdr
|
||||
#define elf_sym elf64_sym
|
||||
#define elf_word uint64_t
|
||||
#define bswapSZs bswap64s
|
||||
#define SZ 64
|
||||
#include "elf_ops.h"
|
||||
#endif
|
||||
|
||||
int load_elf(const char *filename, uint8_t *addr)
|
||||
{
|
||||
struct elfhdr ehdr;
|
||||
struct elf_phdr phdr;
|
||||
struct elf32_hdr ehdr;
|
||||
int retval, fd;
|
||||
Elf32_Half machine;
|
||||
|
||||
fd = open(filename, O_RDONLY | O_BINARY);
|
||||
if (fd < 0)
|
||||
|
@ -272,21 +108,43 @@ int load_elf(const char *filename, uint8_t *addr)
|
|||
if (retval < 0)
|
||||
goto error;
|
||||
|
||||
bswap_ehdr(&ehdr);
|
||||
|
||||
if (ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E'
|
||||
|| ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F'
|
||||
|| (ehdr.e_machine != EM_SPARC
|
||||
&& ehdr.e_machine != EM_SPARC32PLUS))
|
||||
|| ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F')
|
||||
goto error;
|
||||
machine = tswap16(ehdr.e_machine);
|
||||
if (machine == EM_SPARC || machine == EM_SPARC32PLUS) {
|
||||
struct elf32_phdr phdr;
|
||||
|
||||
if (find_phdr(&ehdr, fd, &phdr, PT_LOAD))
|
||||
goto error;
|
||||
retval = read_program(fd, &phdr, addr, ehdr.e_entry);
|
||||
if (retval < 0)
|
||||
goto error;
|
||||
bswap_ehdr32(&ehdr);
|
||||
|
||||
load_symbols(&ehdr, fd);
|
||||
if (find_phdr32(&ehdr, fd, &phdr, PT_LOAD))
|
||||
goto error;
|
||||
retval = read_program32(fd, &phdr, addr, ehdr.e_entry);
|
||||
if (retval < 0)
|
||||
goto error;
|
||||
load_symbols32(&ehdr, fd);
|
||||
}
|
||||
#ifdef TARGET_SPARC64
|
||||
else if (machine == EM_SPARCV9) {
|
||||
struct elf64_hdr ehdr64;
|
||||
struct elf64_phdr phdr;
|
||||
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
|
||||
retval = read(fd, &ehdr64, sizeof(ehdr64));
|
||||
if (retval < 0)
|
||||
goto error;
|
||||
|
||||
bswap_ehdr64(&ehdr64);
|
||||
|
||||
if (find_phdr64(&ehdr64, fd, &phdr, PT_LOAD))
|
||||
goto error;
|
||||
retval = read_program64(fd, &phdr, addr, ehdr64.e_entry);
|
||||
if (retval < 0)
|
||||
goto error;
|
||||
load_symbols64(&ehdr64, fd);
|
||||
}
|
||||
#endif
|
||||
|
||||
close(fd);
|
||||
return retval;
|
||||
|
|
|
@ -144,14 +144,14 @@ static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uin
|
|||
switch (saddr) {
|
||||
case 2: // clear (enable)
|
||||
// Force clear unused bits
|
||||
val &= ~0x7fb2007f;
|
||||
val &= ~0x4fb2007f;
|
||||
s->intregm_disabled &= ~val;
|
||||
DPRINTF("Enabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
|
||||
slavio_check_interrupts(s);
|
||||
break;
|
||||
case 3: // set (disable, clear pending)
|
||||
// Force clear unused bits
|
||||
val &= ~0x7fb2007f;
|
||||
val &= ~0x4fb2007f;
|
||||
s->intregm_disabled |= val;
|
||||
s->intregm_pending &= ~val;
|
||||
DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
|
||||
|
@ -208,7 +208,7 @@ void slavio_irq_info(void *opaque)
|
|||
|
||||
static const uint32_t intbit_to_level[32] = {
|
||||
2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12,
|
||||
6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 0, 0,
|
||||
6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0,
|
||||
};
|
||||
|
||||
static void slavio_check_interrupts(void *opaque)
|
||||
|
|
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
* QEMU Sparc SLAVIO aux io port emulation
|
||||
*
|
||||
* Copyright (c) 2005 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "vl.h"
|
||||
/* debug misc */
|
||||
//#define DEBUG_MISC
|
||||
|
||||
/*
|
||||
* This is the auxio port, chip control and system control part of
|
||||
* chip STP2001 (Slave I/O), also produced as NCR89C105. See
|
||||
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
|
||||
*
|
||||
* This also includes the PMC CPU idle controller.
|
||||
*/
|
||||
|
||||
#ifdef DEBUG_MISC
|
||||
#define MISC_DPRINTF(fmt, args...) \
|
||||
do { printf("MISC: " fmt , ##args); } while (0)
|
||||
#else
|
||||
#define MISC_DPRINTF(fmt, args...)
|
||||
#endif
|
||||
|
||||
typedef struct MiscState {
|
||||
int irq;
|
||||
uint8_t config;
|
||||
uint8_t aux1, aux2;
|
||||
uint8_t diag, mctrl;
|
||||
} MiscState;
|
||||
|
||||
#define MISC_MAXADDR 1
|
||||
|
||||
static void slavio_misc_update_irq(void *opaque)
|
||||
{
|
||||
MiscState *s = opaque;
|
||||
|
||||
if ((s->aux2 & 0x4) && (s->config & 0x8)) {
|
||||
pic_set_irq(s->irq, 1);
|
||||
} else {
|
||||
pic_set_irq(s->irq, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void slavio_misc_reset(void *opaque)
|
||||
{
|
||||
MiscState *s = opaque;
|
||||
|
||||
// Diagnostic register not cleared in reset
|
||||
s->config = s->aux1 = s->aux2 = s->mctrl = 0;
|
||||
}
|
||||
|
||||
void slavio_set_power_fail(void *opaque, int power_failing)
|
||||
{
|
||||
MiscState *s = opaque;
|
||||
|
||||
MISC_DPRINTF("Power fail: %d, config: %d\n", power_failing, s->config);
|
||||
if (power_failing && (s->config & 0x8)) {
|
||||
s->aux2 |= 0x4;
|
||||
} else {
|
||||
s->aux2 &= ~0x4;
|
||||
}
|
||||
slavio_misc_update_irq(s);
|
||||
}
|
||||
|
||||
static void slavio_misc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
MiscState *s = opaque;
|
||||
|
||||
switch (addr & 0xfff0000) {
|
||||
case 0x1800000:
|
||||
MISC_DPRINTF("Write config %2.2x\n", val & 0xff);
|
||||
s->config = val & 0xff;
|
||||
slavio_misc_update_irq(s);
|
||||
break;
|
||||
case 0x1900000:
|
||||
MISC_DPRINTF("Write aux1 %2.2x\n", val & 0xff);
|
||||
s->aux1 = val & 0xff;
|
||||
break;
|
||||
case 0x1910000:
|
||||
val &= 0x3;
|
||||
MISC_DPRINTF("Write aux2 %2.2x\n", val);
|
||||
val |= s->aux2 & 0x4;
|
||||
if (val & 0x2) // Clear Power Fail int
|
||||
val &= 0x1;
|
||||
s->aux2 = val;
|
||||
if (val & 1)
|
||||
qemu_system_shutdown_request();
|
||||
slavio_misc_update_irq(s);
|
||||
break;
|
||||
case 0x1a00000:
|
||||
MISC_DPRINTF("Write diag %2.2x\n", val & 0xff);
|
||||
s->diag = val & 0xff;
|
||||
break;
|
||||
case 0x1b00000:
|
||||
MISC_DPRINTF("Write modem control %2.2x\n", val & 0xff);
|
||||
s->mctrl = val & 0xff;
|
||||
break;
|
||||
case 0x1f00000:
|
||||
MISC_DPRINTF("Write system control %2.2x\n", val & 0xff);
|
||||
if (val & 1)
|
||||
qemu_system_reset_request();
|
||||
break;
|
||||
case 0xa000000:
|
||||
MISC_DPRINTF("Write power management %2.2x\n", val & 0xff);
|
||||
#if 0
|
||||
// XXX: halting CPU does not work
|
||||
raise_exception(EXCP_HLT);
|
||||
cpu_loop_exit();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t slavio_misc_mem_readb(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
MiscState *s = opaque;
|
||||
uint32_t ret = 0;
|
||||
|
||||
switch (addr & 0xfff0000) {
|
||||
case 0x1800000:
|
||||
ret = s->config;
|
||||
MISC_DPRINTF("Read config %2.2x\n", ret);
|
||||
break;
|
||||
case 0x1900000:
|
||||
ret = s->aux1;
|
||||
MISC_DPRINTF("Read aux1 %2.2x\n", ret);
|
||||
break;
|
||||
case 0x1910000:
|
||||
ret = s->aux2;
|
||||
MISC_DPRINTF("Read aux2 %2.2x\n", ret);
|
||||
break;
|
||||
case 0x1a00000:
|
||||
ret = s->diag;
|
||||
MISC_DPRINTF("Read diag %2.2x\n", ret);
|
||||
break;
|
||||
case 0x1b00000:
|
||||
ret = s->mctrl;
|
||||
MISC_DPRINTF("Read modem control %2.2x\n", ret);
|
||||
break;
|
||||
case 0x1f00000:
|
||||
MISC_DPRINTF("Read system control %2.2x\n", ret);
|
||||
break;
|
||||
case 0xa000000:
|
||||
MISC_DPRINTF("Read power management %2.2x\n", ret);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static CPUReadMemoryFunc *slavio_misc_mem_read[3] = {
|
||||
slavio_misc_mem_readb,
|
||||
slavio_misc_mem_readb,
|
||||
slavio_misc_mem_readb,
|
||||
};
|
||||
|
||||
static CPUWriteMemoryFunc *slavio_misc_mem_write[3] = {
|
||||
slavio_misc_mem_writeb,
|
||||
slavio_misc_mem_writeb,
|
||||
slavio_misc_mem_writeb,
|
||||
};
|
||||
|
||||
static void slavio_misc_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
MiscState *s = opaque;
|
||||
|
||||
qemu_put_be32s(f, &s->irq);
|
||||
qemu_put_8s(f, &s->config);
|
||||
qemu_put_8s(f, &s->aux1);
|
||||
qemu_put_8s(f, &s->aux2);
|
||||
qemu_put_8s(f, &s->diag);
|
||||
qemu_put_8s(f, &s->mctrl);
|
||||
}
|
||||
|
||||
static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
MiscState *s = opaque;
|
||||
|
||||
if (version_id != 1)
|
||||
return -EINVAL;
|
||||
|
||||
qemu_get_be32s(f, &s->irq);
|
||||
qemu_get_8s(f, &s->config);
|
||||
qemu_get_8s(f, &s->aux1);
|
||||
qemu_get_8s(f, &s->aux2);
|
||||
qemu_get_8s(f, &s->diag);
|
||||
qemu_get_8s(f, &s->mctrl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *slavio_misc_init(uint32_t base, int irq)
|
||||
{
|
||||
int slavio_misc_io_memory;
|
||||
MiscState *s;
|
||||
|
||||
s = qemu_mallocz(sizeof(MiscState));
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
slavio_misc_io_memory = cpu_register_io_memory(0, slavio_misc_mem_read, slavio_misc_mem_write, s);
|
||||
// Slavio control
|
||||
cpu_register_physical_memory(base + 0x1800000, MISC_MAXADDR, slavio_misc_io_memory);
|
||||
// AUX 1
|
||||
cpu_register_physical_memory(base + 0x1900000, MISC_MAXADDR, slavio_misc_io_memory);
|
||||
// AUX 2
|
||||
cpu_register_physical_memory(base + 0x1910000, MISC_MAXADDR, slavio_misc_io_memory);
|
||||
// Diagnostics
|
||||
cpu_register_physical_memory(base + 0x1a00000, MISC_MAXADDR, slavio_misc_io_memory);
|
||||
// Modem control
|
||||
cpu_register_physical_memory(base + 0x1b00000, MISC_MAXADDR, slavio_misc_io_memory);
|
||||
// System control
|
||||
cpu_register_physical_memory(base + 0x1f00000, MISC_MAXADDR, slavio_misc_io_memory);
|
||||
// Power management
|
||||
cpu_register_physical_memory(base + 0xa000000, MISC_MAXADDR, slavio_misc_io_memory);
|
||||
|
||||
s->irq = irq;
|
||||
|
||||
register_savevm("slavio_misc", base, 1, slavio_misc_save, slavio_misc_load, s);
|
||||
qemu_register_reset(slavio_misc_reset, s);
|
||||
slavio_misc_reset(s);
|
||||
return s;
|
||||
}
|
10
hw/sun4m.c
10
hw/sun4m.c
|
@ -37,6 +37,7 @@
|
|||
// bits
|
||||
#define PHYS_JJ_IOMMU 0x10000000 /* I/O MMU */
|
||||
#define PHYS_JJ_TCX_FB 0x50000000 /* TCX frame buffer */
|
||||
#define PHYS_JJ_SLAVIO 0x70000000 /* Slavio base */
|
||||
#define PHYS_JJ_ESPDMA 0x78400000 /* ESP DMA controller */
|
||||
#define PHYS_JJ_ESP 0x78800000 /* ESP SCSI */
|
||||
#define PHYS_JJ_ESP_IRQ 18
|
||||
|
@ -55,6 +56,7 @@
|
|||
#define PHYS_JJ_SER_IRQ 15
|
||||
#define PHYS_JJ_FDC 0x71400000 /* Floppy */
|
||||
#define PHYS_JJ_FLOPPY_IRQ 22
|
||||
#define PHYS_JJ_ME_IRQ 30 /* Module error, power fail */
|
||||
|
||||
/* TSC handling */
|
||||
|
||||
|
@ -202,6 +204,13 @@ uint32_t iommu_translate(uint32_t addr)
|
|||
return iommu_translate_local(iommu, addr);
|
||||
}
|
||||
|
||||
static void *slavio_misc;
|
||||
|
||||
void qemu_system_powerdown(void)
|
||||
{
|
||||
slavio_set_power_fail(slavio_misc, 1);
|
||||
}
|
||||
|
||||
/* Sun4m hardware initialisation */
|
||||
static void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
DisplayState *ds, const char **fd_filename, int snapshot,
|
||||
|
@ -230,6 +239,7 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
|
|||
slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[1], serial_hds[0]);
|
||||
fdctrl_init(PHYS_JJ_FLOPPY_IRQ, 0, 1, PHYS_JJ_FDC, fd_table);
|
||||
esp_init(bs_table, PHYS_JJ_ESP_IRQ, PHYS_JJ_ESP, PHYS_JJ_ESPDMA);
|
||||
slavio_misc = slavio_misc_init(PHYS_JJ_SLAVIO, PHYS_JJ_ME_IRQ);
|
||||
|
||||
prom_offset = ram_size + vram_size;
|
||||
|
||||
|
|
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
* QEMU Sun4u System Emulator
|
||||
*
|
||||
* Copyright (c) 2005 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "vl.h"
|
||||
#include "m48t08.h"
|
||||
|
||||
#define KERNEL_LOAD_ADDR 0x00004000
|
||||
#define CMDLINE_ADDR 0x007ff000
|
||||
#define INITRD_LOAD_ADDR 0x00800000
|
||||
#define PROM_ADDR 0xffd00000
|
||||
#define PROM_FILENAMEB "proll-sparc64.bin"
|
||||
#define PROM_FILENAMEE "proll-sparc64.elf"
|
||||
#define PHYS_JJ_EEPROM 0x71200000 /* m48t08 */
|
||||
#define PHYS_JJ_IDPROM_OFF 0x1FD8
|
||||
#define PHYS_JJ_EEPROM_SIZE 0x2000
|
||||
// IRQs are not PIL ones, but master interrupt controller register
|
||||
// bits
|
||||
#define PHYS_JJ_MS_KBD 0x71000000 /* Mouse and keyboard */
|
||||
#define PHYS_JJ_MS_KBD_IRQ 14
|
||||
#define PHYS_JJ_SER 0x71100000 /* Serial */
|
||||
#define PHYS_JJ_SER_IRQ 15
|
||||
|
||||
/* TSC handling */
|
||||
|
||||
uint64_t cpu_get_tsc()
|
||||
{
|
||||
return qemu_get_clock(vm_clock);
|
||||
}
|
||||
|
||||
int DMA_get_channel_mode (int nchan)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int DMA_read_memory (int nchan, void *buf, int pos, int size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int DMA_write_memory (int nchan, void *buf, int pos, int size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
void DMA_hold_DREQ (int nchan) {}
|
||||
void DMA_release_DREQ (int nchan) {}
|
||||
void DMA_schedule(int nchan) {}
|
||||
void DMA_run (void) {}
|
||||
void DMA_init (int high_page_enable) {}
|
||||
void DMA_register_channel (int nchan,
|
||||
DMA_transfer_handler transfer_handler,
|
||||
void *opaque)
|
||||
{
|
||||
}
|
||||
|
||||
static void nvram_set_word (m48t08_t *nvram, uint32_t addr, uint16_t value)
|
||||
{
|
||||
m48t08_write(nvram, addr++, (value >> 8) & 0xff);
|
||||
m48t08_write(nvram, addr++, value & 0xff);
|
||||
}
|
||||
|
||||
static void nvram_set_lword (m48t08_t *nvram, uint32_t addr, uint32_t value)
|
||||
{
|
||||
m48t08_write(nvram, addr++, value >> 24);
|
||||
m48t08_write(nvram, addr++, (value >> 16) & 0xff);
|
||||
m48t08_write(nvram, addr++, (value >> 8) & 0xff);
|
||||
m48t08_write(nvram, addr++, value & 0xff);
|
||||
}
|
||||
|
||||
static void nvram_set_string (m48t08_t *nvram, uint32_t addr,
|
||||
const unsigned char *str, uint32_t max)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < max && str[i] != '\0'; i++) {
|
||||
m48t08_write(nvram, addr + i, str[i]);
|
||||
}
|
||||
m48t08_write(nvram, addr + max - 1, '\0');
|
||||
}
|
||||
|
||||
static m48t08_t *nvram;
|
||||
|
||||
extern int nographic;
|
||||
|
||||
static void nvram_init(m48t08_t *nvram, uint8_t *macaddr, const char *cmdline,
|
||||
int boot_device, uint32_t RAM_size,
|
||||
uint32_t kernel_size,
|
||||
int width, int height, int depth)
|
||||
{
|
||||
unsigned char tmp = 0;
|
||||
int i, j;
|
||||
|
||||
// Try to match PPC NVRAM
|
||||
nvram_set_string(nvram, 0x00, "QEMU_BIOS", 16);
|
||||
nvram_set_lword(nvram, 0x10, 0x00000001); /* structure v1 */
|
||||
// NVRAM_size, arch not applicable
|
||||
m48t08_write(nvram, 0x2F, nographic & 0xff);
|
||||
nvram_set_lword(nvram, 0x30, RAM_size);
|
||||
m48t08_write(nvram, 0x34, boot_device & 0xff);
|
||||
nvram_set_lword(nvram, 0x38, KERNEL_LOAD_ADDR);
|
||||
nvram_set_lword(nvram, 0x3C, kernel_size);
|
||||
if (cmdline) {
|
||||
strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
|
||||
nvram_set_lword(nvram, 0x40, CMDLINE_ADDR);
|
||||
nvram_set_lword(nvram, 0x44, strlen(cmdline));
|
||||
}
|
||||
// initrd_image, initrd_size passed differently
|
||||
nvram_set_word(nvram, 0x54, width);
|
||||
nvram_set_word(nvram, 0x56, height);
|
||||
nvram_set_word(nvram, 0x58, depth);
|
||||
|
||||
// Sun4m specific use
|
||||
i = 0x1fd8;
|
||||
m48t08_write(nvram, i++, 0x01);
|
||||
m48t08_write(nvram, i++, 0x80); /* Sun4m OBP */
|
||||
j = 0;
|
||||
m48t08_write(nvram, i++, macaddr[j++]);
|
||||
m48t08_write(nvram, i++, macaddr[j++]);
|
||||
m48t08_write(nvram, i++, macaddr[j++]);
|
||||
m48t08_write(nvram, i++, macaddr[j++]);
|
||||
m48t08_write(nvram, i++, macaddr[j++]);
|
||||
m48t08_write(nvram, i, macaddr[j]);
|
||||
|
||||
/* Calculate checksum */
|
||||
for (i = 0x1fd8; i < 0x1fe7; i++) {
|
||||
tmp ^= m48t08_read(nvram, i);
|
||||
}
|
||||
m48t08_write(nvram, 0x1fe7, tmp);
|
||||
}
|
||||
|
||||
void pic_info()
|
||||
{
|
||||
}
|
||||
|
||||
void irq_info()
|
||||
{
|
||||
}
|
||||
|
||||
void pic_set_irq(int irq, int level)
|
||||
{
|
||||
}
|
||||
|
||||
void vga_update_display()
|
||||
{
|
||||
}
|
||||
|
||||
void vga_invalidate_display()
|
||||
{
|
||||
}
|
||||
|
||||
void vga_screen_dump(const char *filename)
|
||||
{
|
||||
}
|
||||
|
||||
void qemu_system_powerdown(void)
|
||||
{
|
||||
}
|
||||
|
||||
/* Sun4u hardware initialisation */
|
||||
static void sun4u_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
DisplayState *ds, const char **fd_filename, int snapshot,
|
||||
const char *kernel_filename, const char *kernel_cmdline,
|
||||
const char *initrd_filename)
|
||||
{
|
||||
char buf[1024];
|
||||
int ret, linux_boot;
|
||||
unsigned int i;
|
||||
long vram_size = 0x100000, prom_offset, initrd_size, kernel_size;
|
||||
|
||||
linux_boot = (kernel_filename != NULL);
|
||||
|
||||
/* allocate RAM */
|
||||
cpu_register_physical_memory(0, ram_size, 0);
|
||||
|
||||
nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE);
|
||||
// Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device
|
||||
// Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device
|
||||
slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[1], serial_hds[0]);
|
||||
|
||||
prom_offset = ram_size + vram_size;
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE);
|
||||
ret = load_elf(buf, phys_ram_base + prom_offset);
|
||||
if (ret < 0) {
|
||||
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB);
|
||||
ret = load_image(buf, phys_ram_base + prom_offset);
|
||||
}
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "qemu: could not load prom '%s'\n",
|
||||
buf);
|
||||
exit(1);
|
||||
}
|
||||
cpu_register_physical_memory(PROM_ADDR, (ret + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK,
|
||||
prom_offset | IO_MEM_ROM);
|
||||
|
||||
kernel_size = 0;
|
||||
if (linux_boot) {
|
||||
kernel_size = load_elf(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
|
||||
if (kernel_size < 0)
|
||||
kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
|
||||
if (kernel_size < 0)
|
||||
kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
|
||||
if (kernel_size < 0) {
|
||||
fprintf(stderr, "qemu: could not load kernel '%s'\n",
|
||||
kernel_filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* load initrd */
|
||||
initrd_size = 0;
|
||||
if (initrd_filename) {
|
||||
initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR);
|
||||
if (initrd_size < 0) {
|
||||
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
|
||||
initrd_filename);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (initrd_size > 0) {
|
||||
for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
|
||||
if (ldl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i)
|
||||
== 0x48647253) { // HdrS
|
||||
stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR);
|
||||
stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 20, initrd_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, boot_device, ram_size, kernel_size, graphic_width, graphic_height, graphic_depth);
|
||||
}
|
||||
|
||||
QEMUMachine sun4u_machine = {
|
||||
"sun4u",
|
||||
"Sun4u platform",
|
||||
sun4u_init,
|
||||
};
|
|
@ -552,6 +552,7 @@ void cpu_loop (CPUSPARCState *env)
|
|||
env->pc = env->npc;
|
||||
env->npc = env->npc + 4;
|
||||
break;
|
||||
#ifndef TARGET_SPARC64
|
||||
case TT_WIN_OVF: /* window overflow */
|
||||
save_window(env);
|
||||
break;
|
||||
|
@ -569,6 +570,9 @@ void cpu_loop (CPUSPARCState *env)
|
|||
queue_signal(info.si_signo, &info);
|
||||
}
|
||||
break;
|
||||
#else
|
||||
// XXX
|
||||
#endif
|
||||
case 0x100: // XXX, why do we get these?
|
||||
break;
|
||||
case EXCP_DEBUG:
|
||||
|
|
|
@ -767,6 +767,11 @@ static void do_system_reset(void)
|
|||
qemu_system_reset_request();
|
||||
}
|
||||
|
||||
static void do_system_powerdown(void)
|
||||
{
|
||||
qemu_system_powerdown_request();
|
||||
}
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
static void print_pte(uint32_t addr, uint32_t pte, uint32_t mask)
|
||||
{
|
||||
|
@ -922,6 +927,8 @@ static term_cmd_t term_cmds[] = {
|
|||
"keys", "send keys to the VM (e.g. 'sendkey ctrl-alt-f1')" },
|
||||
{ "system_reset", "", do_system_reset,
|
||||
"", "reset the system" },
|
||||
{ "system_powerdown", "", do_system_powerdown,
|
||||
"", "send system power down event" },
|
||||
{ "sum", "ii", do_sum,
|
||||
"addr size", "compute the checksum of a memory region" },
|
||||
{ NULL, NULL, },
|
||||
|
|
|
@ -42,10 +42,11 @@ For system emulation, the following hardware targets are supported:
|
|||
@item PC (x86 processor)
|
||||
@item PREP (PowerPC processor)
|
||||
@item PowerMac (PowerPC processor, in progress)
|
||||
@item Sun4m (Sparc processor, in progress)
|
||||
@item Sun4m (32-bit Sparc processor)
|
||||
@item Sun4u (64-bit Sparc processor, in progress)
|
||||
@end itemize
|
||||
|
||||
For user emulation, x86, PowerPC, ARM, and SPARC CPUs are supported.
|
||||
For user emulation, x86, PowerPC, ARM, and Sparc32/64 CPUs are supported.
|
||||
|
||||
@chapter Installation
|
||||
|
||||
|
@ -999,15 +1000,15 @@ Set the initial VGA graphic mode. The default is 800x600x15.
|
|||
More information is available at
|
||||
@url{http://jocelyn.mayer.free.fr/qemu-ppc/}.
|
||||
|
||||
@chapter Sparc System emulator invocation
|
||||
@chapter Sparc32 System emulator invocation
|
||||
|
||||
Use the executable @file{qemu-system-sparc} to simulate a JavaStation
|
||||
(sun4m architecture). The emulation is far from complete.
|
||||
(sun4m architecture). The emulation is somewhat complete.
|
||||
|
||||
QEMU emulates the following sun4m peripherals:
|
||||
|
||||
@itemize @minus
|
||||
@item
|
||||
@item
|
||||
IOMMU
|
||||
@item
|
||||
TCX Frame buffer
|
||||
|
@ -1016,14 +1017,42 @@ Lance (Am7990) Ethernet
|
|||
@item
|
||||
Non Volatile RAM M48T08
|
||||
@item
|
||||
Slave I/O: timers, interrupt controllers, Zilog serial ports
|
||||
Slave I/O: timers, interrupt controllers, Zilog serial ports, keyboard
|
||||
and power/reset logic
|
||||
@item
|
||||
ESP SCSI controller with hard disk and CD-ROM support
|
||||
@item
|
||||
Floppy drive
|
||||
@end itemize
|
||||
|
||||
QEMU uses the Proll, a PROM replacement available at
|
||||
@url{http://people.redhat.com/zaitcev/linux/}.
|
||||
The number of peripherals is fixed in the architecture.
|
||||
|
||||
A sample Linux kernel and ram disk image are available on the QEMU web
|
||||
site.
|
||||
QEMU uses the Proll, a PROM replacement available at
|
||||
@url{http://people.redhat.com/zaitcev/linux/}. The required
|
||||
QEMU-specific patches are included with the sources.
|
||||
|
||||
A sample Linux 2.6 series kernel and ram disk image are available on
|
||||
the QEMU web site. Please note that currently neither Linux 2.4
|
||||
series, NetBSD, nor OpenBSD kernels work.
|
||||
|
||||
@c man begin OPTIONS
|
||||
|
||||
The following options are specific to the Sparc emulation:
|
||||
|
||||
@table @option
|
||||
|
||||
@item -g WxH
|
||||
|
||||
Set the initial TCX graphic mode. The default is 1024x768.
|
||||
|
||||
@end table
|
||||
|
||||
@c man end
|
||||
|
||||
@chapter Sparc64 System emulator invocation
|
||||
|
||||
Use the executable @file{qemu-system-sparc64} to simulate a Sun4u machine.
|
||||
The emulator is not usable for anything yet.
|
||||
|
||||
@chapter QEMU User space emulator invocation
|
||||
|
||||
|
|
|
@ -138,9 +138,32 @@ FPU and MMU.
|
|||
@itemize
|
||||
|
||||
@item Somewhat complete SPARC V8 emulation, including privileged
|
||||
instructions, FPU and MMU.
|
||||
instructions, FPU and MMU. SPARC V9 emulation includes most privileged
|
||||
instructions, FPU and I/D MMU, but misses VIS instructions.
|
||||
|
||||
@item Can run some SPARC Linux binaries.
|
||||
@item Can run some 32-bit SPARC Linux binaries.
|
||||
|
||||
@end itemize
|
||||
|
||||
Current QEMU limitations:
|
||||
|
||||
@itemize
|
||||
|
||||
@item Tagged add/subtract instructions are not supported, but they are
|
||||
probably not used.
|
||||
|
||||
@item IPC syscalls are missing.
|
||||
|
||||
@item 128-bit floating point operations are not supported, though none of the
|
||||
real CPUs implement them either. FCMPE[SD] are not correctly
|
||||
implemented. Floating point exception support is untested.
|
||||
|
||||
@item Alignment is not enforced at all.
|
||||
|
||||
@item Atomic instructions are not correctly implemented.
|
||||
|
||||
@item Sparc64 emulators are not usable for anything yet.
|
||||
Address space is limited to first 4 gigabytes.
|
||||
|
||||
@end itemize
|
||||
|
||||
|
|
|
@ -6,12 +6,11 @@
|
|||
#if !defined(TARGET_SPARC64)
|
||||
#define TARGET_LONG_BITS 32
|
||||
#define TARGET_FPREGS 32
|
||||
#define TARGET_FPREG_T float
|
||||
#else
|
||||
#define TARGET_LONG_BITS 64
|
||||
#define TARGET_FPREGS 64
|
||||
#define TARGET_FPREG_T double
|
||||
#endif
|
||||
#define TARGET_FPREG_T float
|
||||
|
||||
#include "cpu-defs.h"
|
||||
|
||||
|
@ -22,6 +21,7 @@
|
|||
/*#define EXCP_INTERRUPT 0x100*/
|
||||
|
||||
/* trap definitions */
|
||||
#ifndef TARGET_SPARC64
|
||||
#define TT_TFAULT 0x01
|
||||
#define TT_ILL_INSN 0x02
|
||||
#define TT_PRIV_INSN 0x03
|
||||
|
@ -33,6 +33,21 @@
|
|||
#define TT_EXTINT 0x10
|
||||
#define TT_DIV_ZERO 0x2a
|
||||
#define TT_TRAP 0x80
|
||||
#else
|
||||
#define TT_TFAULT 0x08
|
||||
#define TT_ILL_INSN 0x10
|
||||
#define TT_PRIV_INSN 0x11
|
||||
#define TT_NFPU_INSN 0x20
|
||||
#define TT_FP_EXCP 0x21
|
||||
#define TT_CLRWIN 0x24
|
||||
#define TT_DIV_ZERO 0x28
|
||||
#define TT_DFAULT 0x30
|
||||
#define TT_EXTINT 0x40
|
||||
#define TT_SPILL 0x80
|
||||
#define TT_FILL 0xc0
|
||||
#define TT_WOTHER 0x10
|
||||
#define TT_TRAP 0x100
|
||||
#endif
|
||||
|
||||
#define PSR_NEG (1<<23)
|
||||
#define PSR_ZERO (1<<22)
|
||||
|
@ -49,6 +64,13 @@
|
|||
/* Trap base register */
|
||||
#define TBR_BASE_MASK 0xfffff000
|
||||
|
||||
#if defined(TARGET_SPARC64)
|
||||
#define PS_PEF (1<<4)
|
||||
#define PS_AM (1<<3)
|
||||
#define PS_PRIV (1<<2)
|
||||
#define PS_IE (1<<1)
|
||||
#endif
|
||||
|
||||
/* Fcc */
|
||||
#define FSR_RD1 (1<<31)
|
||||
#define FSR_RD0 (1<<30)
|
||||
|
@ -119,15 +141,15 @@ typedef struct CPUSPARCState {
|
|||
target_ulong npc; /* next program counter */
|
||||
target_ulong y; /* multiply/divide register */
|
||||
uint32_t psr; /* processor state register */
|
||||
uint32_t fsr; /* FPU state register */
|
||||
target_ulong fsr; /* FPU state register */
|
||||
uint32_t cwp; /* index of current register window (extracted
|
||||
from PSR) */
|
||||
uint32_t wim; /* window invalid mask */
|
||||
uint32_t tbr; /* trap base register */
|
||||
target_ulong tbr; /* trap base register */
|
||||
int psrs; /* supervisor mode (extracted from PSR) */
|
||||
int psrps; /* previous supervisor mode */
|
||||
int psret; /* enable traps */
|
||||
int psrpil; /* interrupt level */
|
||||
uint32_t psrpil; /* interrupt level */
|
||||
int psref; /* enable fpu */
|
||||
jmp_buf jmp_env;
|
||||
int user_mode_only;
|
||||
|
@ -150,13 +172,43 @@ typedef struct CPUSPARCState {
|
|||
CPUTLBEntry tlb_read[2][CPU_TLB_SIZE];
|
||||
CPUTLBEntry tlb_write[2][CPU_TLB_SIZE];
|
||||
/* MMU regs */
|
||||
#if defined(TARGET_SPARC64)
|
||||
uint64_t lsu;
|
||||
#define DMMU_E 0x8
|
||||
#define IMMU_E 0x4
|
||||
uint64_t immuregs[16];
|
||||
uint64_t dmmuregs[16];
|
||||
uint64_t itlb_tag[64];
|
||||
uint64_t itlb_tte[64];
|
||||
uint64_t dtlb_tag[64];
|
||||
uint64_t dtlb_tte[64];
|
||||
#else
|
||||
uint32_t mmuregs[16];
|
||||
#endif
|
||||
/* temporary float registers */
|
||||
float ft0, ft1, ft2;
|
||||
double dt0, dt1, dt2;
|
||||
float ft0, ft1;
|
||||
double dt0, dt1;
|
||||
float_status fp_status;
|
||||
#if defined(TARGET_SPARC64)
|
||||
target_ulong t0, t1, t2;
|
||||
#define MAXTL 4
|
||||
uint64_t t0, t1, t2;
|
||||
uint64_t tpc[MAXTL];
|
||||
uint64_t tnpc[MAXTL];
|
||||
uint64_t tstate[MAXTL];
|
||||
uint32_t tt[MAXTL];
|
||||
uint32_t xcc; /* Extended integer condition codes */
|
||||
uint32_t asi;
|
||||
uint32_t pstate;
|
||||
uint32_t tl;
|
||||
uint32_t cansave, canrestore, otherwin, wstate, cleanwin;
|
||||
target_ulong agregs[8]; /* alternate general registers */
|
||||
target_ulong igregs[8]; /* interrupt general registers */
|
||||
target_ulong mgregs[8]; /* mmu general registers */
|
||||
uint64_t version;
|
||||
uint64_t fprs;
|
||||
#endif
|
||||
#if !defined(TARGET_SPARC64) && !defined(reg_T2)
|
||||
target_ulong t2;
|
||||
#endif
|
||||
|
||||
/* ice debug support */
|
||||
|
@ -165,6 +217,24 @@ typedef struct CPUSPARCState {
|
|||
int singlestep_enabled; /* XXX: should use CPU single step mode instead */
|
||||
|
||||
} CPUSPARCState;
|
||||
#if defined(TARGET_SPARC64)
|
||||
#define GET_FSR32(env) (env->fsr & 0xcfc1ffff)
|
||||
#define PUT_FSR32(env, val) do { uint32_t _tmp = val; \
|
||||
env->fsr = (_tmp & 0xcfc1c3ff) | (env->fsr & 0x3f00000000ULL); \
|
||||
} while (0)
|
||||
#define GET_FSR64(env) (env->fsr & 0x3fcfc1ffffULL)
|
||||
#define PUT_FSR64(env, val) do { uint64_t _tmp = val; \
|
||||
env->fsr = _tmp & 0x3fcfc1c3ffULL; \
|
||||
} while (0)
|
||||
// Manuf 0x17, version 0x11, mask 0 (UltraSparc-II)
|
||||
#define GET_VER(env) ((0x17ULL << 48) | (0x11ULL << 32) | \
|
||||
(0 << 24) | (MAXTL << 8) | (NWINDOWS - 1))
|
||||
#else
|
||||
#define GET_FSR32(env) (env->fsr)
|
||||
#define PUT_FSR32(env, val) do { uint32_t _tmp = val; \
|
||||
env->fsr = _tmp & 0xcfc1ffff; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
CPUSPARCState *cpu_sparc_init(void);
|
||||
int cpu_sparc_exec(CPUSPARCState *s);
|
||||
|
@ -194,6 +264,14 @@ void cpu_set_cwp(CPUSPARCState *env1, int new_cwp);
|
|||
cpu_set_cwp(env, _tmp & PSR_CWP & (NWINDOWS - 1)); \
|
||||
} while (0)
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
#define GET_CCR(env) ((env->xcc << 4) | (env->psr & PSR_ICC))
|
||||
#define PUT_CCR(env, val) do { int _tmp = val; \
|
||||
env->xcc = _tmp >> 4; \
|
||||
env->psr = (_tmp & 0xf) << 20; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
struct siginfo;
|
||||
int cpu_sparc_signal_handler(int hostsignum, struct siginfo *info, void *puc);
|
||||
|
||||
|
|
|
@ -1,23 +1,41 @@
|
|||
#ifndef EXEC_SPARC_H
|
||||
#define EXEC_SPARC_H 1
|
||||
#include "dyngen-exec.h"
|
||||
#include "config.h"
|
||||
|
||||
register struct CPUSPARCState *env asm(AREG0);
|
||||
#ifdef TARGET_SPARC64
|
||||
#define T0 (env->t0)
|
||||
#define T1 (env->t1)
|
||||
#define T2 (env->t2)
|
||||
#define REGWPTR env->regwptr
|
||||
#else
|
||||
register uint32_t T0 asm(AREG1);
|
||||
register uint32_t T1 asm(AREG2);
|
||||
register uint32_t T2 asm(AREG3);
|
||||
|
||||
#undef REG_REGWPTR // Broken
|
||||
#ifdef REG_REGWPTR
|
||||
register uint32_t *REGWPTR asm(AREG3);
|
||||
#define reg_REGWPTR
|
||||
|
||||
#ifdef AREG4
|
||||
register uint32_t T2 asm(AREG4);
|
||||
#define reg_T2
|
||||
#else
|
||||
#define T2 (env->t2)
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define REGWPTR env->regwptr
|
||||
register uint32_t T2 asm(AREG3);
|
||||
#define reg_T2
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define FT0 (env->ft0)
|
||||
#define FT1 (env->ft1)
|
||||
#define FT2 (env->ft2)
|
||||
#define DT0 (env->dt0)
|
||||
#define DT1 (env->dt1)
|
||||
#define DT2 (env->dt2)
|
||||
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
|
@ -38,6 +56,16 @@ void do_fsqrts(void);
|
|||
void do_fsqrtd(void);
|
||||
void do_fcmps(void);
|
||||
void do_fcmpd(void);
|
||||
#ifdef TARGET_SPARC64
|
||||
void do_fabsd(void);
|
||||
void do_fcmps_fcc1(void);
|
||||
void do_fcmpd_fcc1(void);
|
||||
void do_fcmps_fcc2(void);
|
||||
void do_fcmpd_fcc2(void);
|
||||
void do_fcmps_fcc3(void);
|
||||
void do_fcmpd_fcc3(void);
|
||||
void do_popc();
|
||||
#endif
|
||||
void do_ldd_kernel(target_ulong addr);
|
||||
void do_ldd_user(target_ulong addr);
|
||||
void do_ldd_raw(target_ulong addr);
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
/* FCC1:FCC0: 0 =, 1 <, 2 >, 3 u */
|
||||
|
||||
void OPPROTO glue(op_eval_fbne, FCC)(void)
|
||||
{
|
||||
// !0
|
||||
T2 = FFLAG_SET(FSR_FCC0) | FFLAG_SET(FSR_FCC1); /* L or G or U */
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_eval_fblg, FCC)(void)
|
||||
{
|
||||
// 1 or 2
|
||||
T2 = FFLAG_SET(FSR_FCC0) ^ FFLAG_SET(FSR_FCC1);
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_eval_fbul, FCC)(void)
|
||||
{
|
||||
// 1 or 3
|
||||
T2 = FFLAG_SET(FSR_FCC0);
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_eval_fbl, FCC)(void)
|
||||
{
|
||||
// 1
|
||||
T2 = FFLAG_SET(FSR_FCC0) & !FFLAG_SET(FSR_FCC1);
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_eval_fbug, FCC)(void)
|
||||
{
|
||||
// 2 or 3
|
||||
T2 = FFLAG_SET(FSR_FCC1);
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_eval_fbg, FCC)(void)
|
||||
{
|
||||
// 2
|
||||
T2 = !FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1);
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_eval_fbu, FCC)(void)
|
||||
{
|
||||
// 3
|
||||
T2 = FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1);
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_eval_fbe, FCC)(void)
|
||||
{
|
||||
// 0
|
||||
T2 = !FFLAG_SET(FSR_FCC0) & !FFLAG_SET(FSR_FCC1);
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_eval_fbue, FCC)(void)
|
||||
{
|
||||
// 0 or 3
|
||||
T2 = !(FFLAG_SET(FSR_FCC1) ^ FFLAG_SET(FSR_FCC0));
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_eval_fbge, FCC)(void)
|
||||
{
|
||||
// 0 or 2
|
||||
T2 = !FFLAG_SET(FSR_FCC0);
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_eval_fbuge, FCC)(void)
|
||||
{
|
||||
// !1
|
||||
T2 = !(FFLAG_SET(FSR_FCC0) & !FFLAG_SET(FSR_FCC1));
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_eval_fble, FCC)(void)
|
||||
{
|
||||
// 0 or 1
|
||||
T2 = !FFLAG_SET(FSR_FCC1);
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_eval_fbule, FCC)(void)
|
||||
{
|
||||
// !2
|
||||
T2 = !(!FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1));
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_eval_fbo, FCC)(void)
|
||||
{
|
||||
// !3
|
||||
T2 = !(FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1));
|
||||
}
|
||||
|
||||
#undef FCC
|
||||
#undef FFLAG_SET
|
|
@ -40,16 +40,6 @@ void OPPROTO glue(op_store_FT1_fpr_fpr, REGNAME)(void)
|
|||
REG = FT1;
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_load_fpr_FT2_fpr, REGNAME)(void)
|
||||
{
|
||||
FT2 = REG;
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_store_FT2_fpr_fpr, REGNAME)(void)
|
||||
{
|
||||
REG = FT2;
|
||||
}
|
||||
|
||||
/* double floating point registers moves */
|
||||
void OPPROTO glue(op_load_fpr_DT0_fpr, REGNAME)(void)
|
||||
{
|
||||
|
@ -87,23 +77,5 @@ void OPPROTO glue(op_store_DT1_fpr_fpr, REGNAME)(void)
|
|||
*p = u.l.upper;
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_load_fpr_DT2_fpr, REGNAME)(void)
|
||||
{
|
||||
CPU_DoubleU u;
|
||||
uint32_t *p = (uint32_t *)®
|
||||
u.l.lower = *(p +1);
|
||||
u.l.upper = *p;
|
||||
DT2 = u.d;
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_store_DT2_fpr_fpr, REGNAME)(void)
|
||||
{
|
||||
CPU_DoubleU u;
|
||||
uint32_t *p = (uint32_t *)®
|
||||
u.d = DT2;
|
||||
*(p +1) = u.l.lower;
|
||||
*p = u.l.upper;
|
||||
}
|
||||
|
||||
#undef REG
|
||||
#undef REGNAME
|
||||
|
|
|
@ -43,7 +43,6 @@ void cpu_unlock(void)
|
|||
int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
|
||||
int is_user, int is_softmmu)
|
||||
{
|
||||
env->mmuregs[4] = address;
|
||||
if (rw & 2)
|
||||
env->exception_index = TT_TFAULT;
|
||||
else
|
||||
|
@ -102,6 +101,7 @@ void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr)
|
|||
env = saved_env;
|
||||
}
|
||||
|
||||
#ifndef TARGET_SPARC64
|
||||
static const int access_table[8][8] = {
|
||||
{ 0, 0, 0, 0, 2, 0, 3, 3 },
|
||||
{ 0, 0, 0, 0, 2, 0, 0, 0 },
|
||||
|
@ -268,6 +268,136 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
static int get_physical_address_data(CPUState *env, target_phys_addr_t *physical, int *prot,
|
||||
int *access_index, target_ulong address, int rw,
|
||||
int is_user)
|
||||
{
|
||||
target_ulong mask;
|
||||
unsigned int i;
|
||||
|
||||
if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
|
||||
*physical = address & 0xffffffff;
|
||||
*prot = PAGE_READ | PAGE_WRITE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) {
|
||||
switch (env->dtlb_tte[i] >> 60) {
|
||||
default:
|
||||
case 0x4: // 8k
|
||||
mask = 0xffffffffffffe000ULL;
|
||||
break;
|
||||
case 0x5: // 64k
|
||||
mask = 0xffffffffffff0000ULL;
|
||||
break;
|
||||
case 0x6: // 512k
|
||||
mask = 0xfffffffffff80000ULL;
|
||||
break;
|
||||
case 0x7: // 4M
|
||||
mask = 0xffffffffffc00000ULL;
|
||||
break;
|
||||
}
|
||||
// ctx match, vaddr match?
|
||||
if (env->dmmuregs[1] == (env->dtlb_tag[i] & 0x1fff) &&
|
||||
(address & mask) == (env->dtlb_tag[i] & ~0x1fffULL)) {
|
||||
// access ok?
|
||||
if (((env->dtlb_tte[i] & 0x4) && !(env->pstate & PS_PRIV)) ||
|
||||
(!(env->dtlb_tte[i] & 0x2) && (rw == 1))) {
|
||||
env->exception_index = TT_DFAULT;
|
||||
return 1;
|
||||
}
|
||||
*physical = env->dtlb_tte[i] & 0xffffe000;
|
||||
*prot = PAGE_READ;
|
||||
if (env->dtlb_tte[i] & 0x2)
|
||||
*prot |= PAGE_WRITE;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
env->exception_index = TT_DFAULT;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int get_physical_address_code(CPUState *env, target_phys_addr_t *physical, int *prot,
|
||||
int *access_index, target_ulong address, int rw,
|
||||
int is_user)
|
||||
{
|
||||
target_ulong mask;
|
||||
unsigned int i;
|
||||
|
||||
if ((env->lsu & IMMU_E) == 0) { /* IMMU disabled */
|
||||
*physical = address & 0xffffffff;
|
||||
*prot = PAGE_READ;
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < 64; i++) {
|
||||
if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) {
|
||||
switch (env->itlb_tte[i] >> 60) {
|
||||
default:
|
||||
case 0x4: // 8k
|
||||
mask = 0xffffffffffffe000ULL;
|
||||
break;
|
||||
case 0x5: // 64k
|
||||
mask = 0xffffffffffff0000ULL;
|
||||
break;
|
||||
case 0x6: // 512k
|
||||
mask = 0xfffffffffff80000ULL;
|
||||
break;
|
||||
case 0x7: // 4M
|
||||
mask = 0xffffffffffc00000ULL;
|
||||
break;
|
||||
}
|
||||
// ctx match, vaddr match?
|
||||
if (env->immuregs[1] == (env->itlb_tag[i] & 0x1fff) &&
|
||||
(address & mask) == (env->itlb_tag[i] & ~0x1fffULL)) {
|
||||
// access ok?
|
||||
if ((env->itlb_tte[i] & 0x4) && !(env->pstate & PS_PRIV)) {
|
||||
env->exception_index = TT_TFAULT;
|
||||
return 1;
|
||||
}
|
||||
*physical = env->itlb_tte[i] & 0xffffe000;
|
||||
*prot = PAGE_READ;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
env->exception_index = TT_TFAULT;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int get_physical_address(CPUState *env, target_phys_addr_t *physical, int *prot,
|
||||
int *access_index, target_ulong address, int rw,
|
||||
int is_user)
|
||||
{
|
||||
if (rw == 2)
|
||||
return get_physical_address_code(env, physical, prot, access_index, address, rw, is_user);
|
||||
else
|
||||
return get_physical_address_data(env, physical, prot, access_index, address, rw, is_user);
|
||||
}
|
||||
|
||||
/* Perform address translation */
|
||||
int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
||||
int is_user, int is_softmmu)
|
||||
{
|
||||
target_ulong virt_addr;
|
||||
target_phys_addr_t paddr;
|
||||
unsigned long vaddr;
|
||||
int error_code = 0, prot, ret = 0, access_index;
|
||||
|
||||
error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user);
|
||||
if (error_code == 0) {
|
||||
virt_addr = address & TARGET_PAGE_MASK;
|
||||
vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1));
|
||||
ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
|
||||
return ret;
|
||||
}
|
||||
// XXX
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void memcpy32(target_ulong *dst, const target_ulong *src)
|
||||
|
@ -292,17 +422,73 @@ void set_cwp(int new_cwp)
|
|||
if (new_cwp == (NWINDOWS - 1))
|
||||
memcpy32(env->regbase + NWINDOWS * 16, env->regbase);
|
||||
env->regwptr = env->regbase + (new_cwp * 16);
|
||||
REGWPTR = env->regwptr;
|
||||
}
|
||||
|
||||
void cpu_set_cwp(CPUState *env1, int new_cwp)
|
||||
{
|
||||
CPUState *saved_env;
|
||||
#ifdef reg_REGWPTR
|
||||
target_ulong *saved_regwptr;
|
||||
#endif
|
||||
|
||||
saved_env = env;
|
||||
#ifdef reg_REGWPTR
|
||||
saved_regwptr = REGWPTR;
|
||||
#endif
|
||||
env = env1;
|
||||
set_cwp(new_cwp);
|
||||
env = saved_env;
|
||||
#ifdef reg_REGWPTR
|
||||
REGWPTR = saved_regwptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
void do_interrupt(int intno)
|
||||
{
|
||||
#ifdef DEBUG_PCALL
|
||||
if (loglevel & CPU_LOG_INT) {
|
||||
static int count;
|
||||
fprintf(logfile, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n",
|
||||
count, intno,
|
||||
env->pc,
|
||||
env->npc, env->regwptr[6]);
|
||||
cpu_dump_state(env, logfile, fprintf, 0);
|
||||
#if 0
|
||||
{
|
||||
int i;
|
||||
uint8_t *ptr;
|
||||
|
||||
fprintf(logfile, " code=");
|
||||
ptr = (uint8_t *)env->pc;
|
||||
for(i = 0; i < 16; i++) {
|
||||
fprintf(logfile, " %02x", ldub(ptr + i));
|
||||
}
|
||||
fprintf(logfile, "\n");
|
||||
}
|
||||
#endif
|
||||
count++;
|
||||
}
|
||||
#endif
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (env->pstate & PS_IE) {
|
||||
cpu_abort(cpu_single_env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
env->tstate[env->tl] = ((uint64_t)GET_CCR(env) << 32) | ((env->asi & 0xff) << 24) |
|
||||
((env->pstate & 0xfff) << 8) | (env->cwp & 0xff);
|
||||
env->tpc[env->tl] = env->pc;
|
||||
env->tnpc[env->tl] = env->npc;
|
||||
env->tt[env->tl] = intno;
|
||||
env->tbr = env->tbr | (env->tl > 1) ? 1 << 14 : 0 | (intno << 4);
|
||||
env->tl++;
|
||||
env->pc = env->tbr;
|
||||
env->npc = env->pc + 4;
|
||||
env->exception_index = 0;
|
||||
}
|
||||
#else
|
||||
void do_interrupt(int intno)
|
||||
{
|
||||
int cwp;
|
||||
|
@ -448,3 +634,4 @@ void dump_mmu(void)
|
|||
printf("MMU dump ends\n");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -25,6 +25,13 @@ void do_fabss(void)
|
|||
FT0 = float32_abs(FT1);
|
||||
}
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
void do_fabsd(void)
|
||||
{
|
||||
DT0 = float64_abs(DT1);
|
||||
}
|
||||
#endif
|
||||
|
||||
void do_fsqrts(void)
|
||||
{
|
||||
FT0 = float32_sqrt(FT1, &env->fp_status);
|
||||
|
@ -35,48 +42,185 @@ void do_fsqrtd(void)
|
|||
DT0 = float64_sqrt(DT1, &env->fp_status);
|
||||
}
|
||||
|
||||
#define FS 0
|
||||
void do_fcmps (void)
|
||||
{
|
||||
env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);
|
||||
if (isnan(FT0) || isnan(FT1)) {
|
||||
T0 = FSR_FCC1 | FSR_FCC0;
|
||||
env->fsr &= ~(FSR_FCC1 | FSR_FCC0);
|
||||
env->fsr |= T0;
|
||||
T0 = (FSR_FCC1 | FSR_FCC0) << FS;
|
||||
if (env->fsr & FSR_NVM) {
|
||||
env->fsr |= T0;
|
||||
raise_exception(TT_FP_EXCP);
|
||||
} else {
|
||||
env->fsr |= FSR_NVA;
|
||||
}
|
||||
} else if (FT0 < FT1) {
|
||||
T0 = FSR_FCC0;
|
||||
T0 = FSR_FCC0 << FS;
|
||||
} else if (FT0 > FT1) {
|
||||
T0 = FSR_FCC1;
|
||||
T0 = FSR_FCC1 << FS;
|
||||
} else {
|
||||
T0 = 0;
|
||||
}
|
||||
env->fsr = T0;
|
||||
env->fsr |= T0;
|
||||
}
|
||||
|
||||
void do_fcmpd (void)
|
||||
{
|
||||
env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);
|
||||
if (isnan(DT0) || isnan(DT1)) {
|
||||
T0 = FSR_FCC1 | FSR_FCC0;
|
||||
env->fsr &= ~(FSR_FCC1 | FSR_FCC0);
|
||||
env->fsr |= T0;
|
||||
T0 = (FSR_FCC1 | FSR_FCC0) << FS;
|
||||
if (env->fsr & FSR_NVM) {
|
||||
env->fsr |= T0;
|
||||
raise_exception(TT_FP_EXCP);
|
||||
} else {
|
||||
env->fsr |= FSR_NVA;
|
||||
}
|
||||
} else if (DT0 < DT1) {
|
||||
T0 = FSR_FCC0;
|
||||
T0 = FSR_FCC0 << FS;
|
||||
} else if (DT0 > DT1) {
|
||||
T0 = FSR_FCC1;
|
||||
T0 = FSR_FCC1 << FS;
|
||||
} else {
|
||||
T0 = 0;
|
||||
}
|
||||
env->fsr = T0;
|
||||
env->fsr |= T0;
|
||||
}
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
#undef FS
|
||||
#define FS 22
|
||||
void do_fcmps_fcc1 (void)
|
||||
{
|
||||
env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);
|
||||
if (isnan(FT0) || isnan(FT1)) {
|
||||
T0 = (FSR_FCC1 | FSR_FCC0) << FS;
|
||||
if (env->fsr & FSR_NVM) {
|
||||
env->fsr |= T0;
|
||||
raise_exception(TT_FP_EXCP);
|
||||
} else {
|
||||
env->fsr |= FSR_NVA;
|
||||
}
|
||||
} else if (FT0 < FT1) {
|
||||
T0 = FSR_FCC0 << FS;
|
||||
} else if (FT0 > FT1) {
|
||||
T0 = FSR_FCC1 << FS;
|
||||
} else {
|
||||
T0 = 0;
|
||||
}
|
||||
env->fsr |= T0;
|
||||
}
|
||||
|
||||
void do_fcmpd_fcc1 (void)
|
||||
{
|
||||
env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);
|
||||
if (isnan(DT0) || isnan(DT1)) {
|
||||
T0 = (FSR_FCC1 | FSR_FCC0) << FS;
|
||||
if (env->fsr & FSR_NVM) {
|
||||
env->fsr |= T0;
|
||||
raise_exception(TT_FP_EXCP);
|
||||
} else {
|
||||
env->fsr |= FSR_NVA;
|
||||
}
|
||||
} else if (DT0 < DT1) {
|
||||
T0 = FSR_FCC0 << FS;
|
||||
} else if (DT0 > DT1) {
|
||||
T0 = FSR_FCC1 << FS;
|
||||
} else {
|
||||
T0 = 0;
|
||||
}
|
||||
env->fsr |= T0;
|
||||
}
|
||||
|
||||
#undef FS
|
||||
#define FS 24
|
||||
void do_fcmps_fcc2 (void)
|
||||
{
|
||||
env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);
|
||||
if (isnan(FT0) || isnan(FT1)) {
|
||||
T0 = (FSR_FCC1 | FSR_FCC0) << FS;
|
||||
if (env->fsr & FSR_NVM) {
|
||||
env->fsr |= T0;
|
||||
raise_exception(TT_FP_EXCP);
|
||||
} else {
|
||||
env->fsr |= FSR_NVA;
|
||||
}
|
||||
} else if (FT0 < FT1) {
|
||||
T0 = FSR_FCC0 << FS;
|
||||
} else if (FT0 > FT1) {
|
||||
T0 = FSR_FCC1 << FS;
|
||||
} else {
|
||||
T0 = 0;
|
||||
}
|
||||
env->fsr |= T0;
|
||||
}
|
||||
|
||||
void do_fcmpd_fcc2 (void)
|
||||
{
|
||||
env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);
|
||||
if (isnan(DT0) || isnan(DT1)) {
|
||||
T0 = (FSR_FCC1 | FSR_FCC0) << FS;
|
||||
if (env->fsr & FSR_NVM) {
|
||||
env->fsr |= T0;
|
||||
raise_exception(TT_FP_EXCP);
|
||||
} else {
|
||||
env->fsr |= FSR_NVA;
|
||||
}
|
||||
} else if (DT0 < DT1) {
|
||||
T0 = FSR_FCC0 << FS;
|
||||
} else if (DT0 > DT1) {
|
||||
T0 = FSR_FCC1 << FS;
|
||||
} else {
|
||||
T0 = 0;
|
||||
}
|
||||
env->fsr |= T0;
|
||||
}
|
||||
|
||||
#undef FS
|
||||
#define FS 26
|
||||
void do_fcmps_fcc3 (void)
|
||||
{
|
||||
env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);
|
||||
if (isnan(FT0) || isnan(FT1)) {
|
||||
T0 = (FSR_FCC1 | FSR_FCC0) << FS;
|
||||
if (env->fsr & FSR_NVM) {
|
||||
env->fsr |= T0;
|
||||
raise_exception(TT_FP_EXCP);
|
||||
} else {
|
||||
env->fsr |= FSR_NVA;
|
||||
}
|
||||
} else if (FT0 < FT1) {
|
||||
T0 = FSR_FCC0 << FS;
|
||||
} else if (FT0 > FT1) {
|
||||
T0 = FSR_FCC1 << FS;
|
||||
} else {
|
||||
T0 = 0;
|
||||
}
|
||||
env->fsr |= T0;
|
||||
}
|
||||
|
||||
void do_fcmpd_fcc3 (void)
|
||||
{
|
||||
env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);
|
||||
if (isnan(DT0) || isnan(DT1)) {
|
||||
T0 = (FSR_FCC1 | FSR_FCC0) << FS;
|
||||
if (env->fsr & FSR_NVM) {
|
||||
env->fsr |= T0;
|
||||
raise_exception(TT_FP_EXCP);
|
||||
} else {
|
||||
env->fsr |= FSR_NVA;
|
||||
}
|
||||
} else if (DT0 < DT1) {
|
||||
T0 = FSR_FCC0 << FS;
|
||||
} else if (DT0 > DT1) {
|
||||
T0 = FSR_FCC1 << FS;
|
||||
} else {
|
||||
T0 = 0;
|
||||
}
|
||||
env->fsr |= T0;
|
||||
}
|
||||
#undef FS
|
||||
#endif
|
||||
|
||||
#ifndef TARGET_SPARC64
|
||||
void helper_ld_asi(int asi, int size, int sign)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
@ -235,6 +379,255 @@ void helper_st_asi(int asi, int size, int sign)
|
|||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void helper_ld_asi(int asi, int size, int sign)
|
||||
{
|
||||
uint64_t ret;
|
||||
|
||||
if (asi < 0x80 && (env->pstate & PS_PRIV) == 0)
|
||||
raise_exception(TT_PRIV_INSN);
|
||||
|
||||
switch (asi) {
|
||||
case 0x14: // Bypass
|
||||
case 0x15: // Bypass, non-cacheable
|
||||
{
|
||||
cpu_physical_memory_read(T0, (void *) &ret, size);
|
||||
if (size == 8)
|
||||
tswap64s(&ret);
|
||||
if (size == 4)
|
||||
tswap32s((uint32_t *)&ret);
|
||||
else if (size == 2)
|
||||
tswap16s((uint16_t *)&ret);
|
||||
break;
|
||||
}
|
||||
case 0x1c: // Bypass LE
|
||||
case 0x1d: // Bypass, non-cacheable LE
|
||||
// XXX
|
||||
break;
|
||||
case 0x45: // LSU
|
||||
ret = env->lsu;
|
||||
break;
|
||||
case 0x50: // I-MMU regs
|
||||
{
|
||||
int reg = (T0 >> 3) & 0xf;
|
||||
|
||||
ret = env->immuregs[reg];
|
||||
break;
|
||||
}
|
||||
case 0x51: // I-MMU 8k TSB pointer
|
||||
case 0x52: // I-MMU 64k TSB pointer
|
||||
case 0x55: // I-MMU data access
|
||||
case 0x56: // I-MMU tag read
|
||||
break;
|
||||
case 0x58: // D-MMU regs
|
||||
{
|
||||
int reg = (T0 >> 3) & 0xf;
|
||||
|
||||
ret = env->dmmuregs[reg];
|
||||
break;
|
||||
}
|
||||
case 0x59: // D-MMU 8k TSB pointer
|
||||
case 0x5a: // D-MMU 64k TSB pointer
|
||||
case 0x5b: // D-MMU data pointer
|
||||
case 0x5d: // D-MMU data access
|
||||
case 0x5e: // D-MMU tag read
|
||||
break;
|
||||
case 0x54: // I-MMU data in, WO
|
||||
case 0x57: // I-MMU demap, WO
|
||||
case 0x5c: // D-MMU data in, WO
|
||||
case 0x5f: // D-MMU demap, WO
|
||||
default:
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
T1 = ret;
|
||||
}
|
||||
|
||||
void helper_st_asi(int asi, int size, int sign)
|
||||
{
|
||||
if (asi < 0x80 && (env->pstate & PS_PRIV) == 0)
|
||||
raise_exception(TT_PRIV_INSN);
|
||||
|
||||
switch(asi) {
|
||||
case 0x14: // Bypass
|
||||
case 0x15: // Bypass, non-cacheable
|
||||
{
|
||||
target_ulong temp = T1;
|
||||
if (size == 8)
|
||||
tswap64s(&temp);
|
||||
else if (size == 4)
|
||||
tswap32s((uint32_t *)&temp);
|
||||
else if (size == 2)
|
||||
tswap16s((uint16_t *)&temp);
|
||||
cpu_physical_memory_write(T0, (void *) &temp, size);
|
||||
}
|
||||
return;
|
||||
case 0x1c: // Bypass LE
|
||||
case 0x1d: // Bypass, non-cacheable LE
|
||||
// XXX
|
||||
return;
|
||||
case 0x45: // LSU
|
||||
{
|
||||
uint64_t oldreg;
|
||||
|
||||
oldreg = env->lsu;
|
||||
env->lsu = T1 & (DMMU_E | IMMU_E);
|
||||
// Mappings generated during D/I MMU disabled mode are
|
||||
// invalid in normal mode
|
||||
if (oldreg != env->lsu)
|
||||
tlb_flush(env, 1);
|
||||
return;
|
||||
}
|
||||
case 0x50: // I-MMU regs
|
||||
{
|
||||
int reg = (T0 >> 3) & 0xf;
|
||||
uint64_t oldreg;
|
||||
|
||||
oldreg = env->immuregs[reg];
|
||||
switch(reg) {
|
||||
case 0: // RO
|
||||
case 4:
|
||||
return;
|
||||
case 1: // Not in I-MMU
|
||||
case 2:
|
||||
case 7:
|
||||
case 8:
|
||||
return;
|
||||
case 3: // SFSR
|
||||
if ((T1 & 1) == 0)
|
||||
T1 = 0; // Clear SFSR
|
||||
break;
|
||||
case 5: // TSB access
|
||||
case 6: // Tag access
|
||||
default:
|
||||
break;
|
||||
}
|
||||
env->immuregs[reg] = T1;
|
||||
#ifdef DEBUG_MMU
|
||||
if (oldreg != env->immuregs[reg]) {
|
||||
printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->immuregs[reg]);
|
||||
}
|
||||
dump_mmu();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
case 0x54: // I-MMU data in
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
// Try finding an invalid entry
|
||||
for (i = 0; i < 64; i++) {
|
||||
if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0) {
|
||||
env->itlb_tag[i] = env->immuregs[6];
|
||||
env->itlb_tte[i] = T1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Try finding an unlocked entry
|
||||
for (i = 0; i < 64; i++) {
|
||||
if ((env->itlb_tte[i] & 0x40) == 0) {
|
||||
env->itlb_tag[i] = env->immuregs[6];
|
||||
env->itlb_tte[i] = T1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// error state?
|
||||
return;
|
||||
}
|
||||
case 0x55: // I-MMU data access
|
||||
{
|
||||
unsigned int i = (T0 >> 3) & 0x3f;
|
||||
|
||||
env->itlb_tag[i] = env->immuregs[6];
|
||||
env->itlb_tte[i] = T1;
|
||||
return;
|
||||
}
|
||||
case 0x57: // I-MMU demap
|
||||
return;
|
||||
case 0x58: // D-MMU regs
|
||||
{
|
||||
int reg = (T0 >> 3) & 0xf;
|
||||
uint64_t oldreg;
|
||||
|
||||
oldreg = env->dmmuregs[reg];
|
||||
switch(reg) {
|
||||
case 0: // RO
|
||||
case 4:
|
||||
return;
|
||||
case 3: // SFSR
|
||||
if ((T1 & 1) == 0) {
|
||||
T1 = 0; // Clear SFSR, Fault address
|
||||
env->dmmuregs[4] = 0;
|
||||
}
|
||||
env->dmmuregs[reg] = T1;
|
||||
break;
|
||||
case 1: // Primary context
|
||||
case 2: // Secondary context
|
||||
case 5: // TSB access
|
||||
case 6: // Tag access
|
||||
case 7: // Virtual Watchpoint
|
||||
case 8: // Physical Watchpoint
|
||||
default:
|
||||
break;
|
||||
}
|
||||
env->dmmuregs[reg] = T1;
|
||||
#ifdef DEBUG_MMU
|
||||
if (oldreg != env->dmmuregs[reg]) {
|
||||
printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->dmmuregs[reg]);
|
||||
}
|
||||
dump_mmu();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
case 0x5c: // D-MMU data in
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
// Try finding an invalid entry
|
||||
for (i = 0; i < 64; i++) {
|
||||
if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0) {
|
||||
env->dtlb_tag[i] = env->dmmuregs[6];
|
||||
env->dtlb_tte[i] = T1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Try finding an unlocked entry
|
||||
for (i = 0; i < 64; i++) {
|
||||
if ((env->dtlb_tte[i] & 0x40) == 0) {
|
||||
env->dtlb_tag[i] = env->dmmuregs[6];
|
||||
env->dtlb_tte[i] = T1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// error state?
|
||||
return;
|
||||
}
|
||||
case 0x5d: // D-MMU data access
|
||||
{
|
||||
unsigned int i = (T0 >> 3) & 0x3f;
|
||||
|
||||
env->dtlb_tag[i] = env->dmmuregs[6];
|
||||
env->dtlb_tte[i] = T1;
|
||||
return;
|
||||
}
|
||||
case 0x5f: // D-MMU demap
|
||||
return;
|
||||
case 0x51: // I-MMU 8k TSB pointer, RO
|
||||
case 0x52: // I-MMU 64k TSB pointer, RO
|
||||
case 0x56: // I-MMU tag read, RO
|
||||
case 0x59: // D-MMU 8k TSB pointer, RO
|
||||
case 0x5a: // D-MMU 64k TSB pointer, RO
|
||||
case 0x5b: // D-MMU data pointer, RO
|
||||
case 0x5e: // D-MMU tag read, RO
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef TARGET_SPARC64
|
||||
void helper_rett()
|
||||
{
|
||||
unsigned int cwp;
|
||||
|
@ -247,6 +640,7 @@ void helper_rett()
|
|||
set_cwp(cwp);
|
||||
env->psrs = env->psrps;
|
||||
}
|
||||
#endif
|
||||
|
||||
void helper_ldfsr(void)
|
||||
{
|
||||
|
@ -288,6 +682,7 @@ void helper_debug()
|
|||
cpu_loop_exit();
|
||||
}
|
||||
|
||||
#ifndef TARGET_SPARC64
|
||||
void do_wrpsr()
|
||||
{
|
||||
PUT_PSR(env, T0);
|
||||
|
@ -297,3 +692,16 @@ void do_rdpsr()
|
|||
{
|
||||
T0 = GET_PSR(env);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void do_popc()
|
||||
{
|
||||
T0 = (T1 & 0x5555555555555555ULL) + ((T1 >> 1) & 0x5555555555555555ULL);
|
||||
T0 = (T0 & 0x3333333333333333ULL) + ((T0 >> 2) & 0x3333333333333333ULL);
|
||||
T0 = (T0 & 0x0f0f0f0f0f0f0f0fULL) + ((T0 >> 4) & 0x0f0f0f0f0f0f0f0fULL);
|
||||
T0 = (T0 & 0x00ff00ff00ff00ffULL) + ((T0 >> 8) & 0x00ff00ff00ff00ffULL);
|
||||
T0 = (T0 & 0x0000ffff0000ffffULL) + ((T0 >> 16) & 0x0000ffff0000ffffULL);
|
||||
T0 = (T0 & 0x00000000ffffffffULL) + ((T0 >> 32) & 0x00000000ffffffffULL);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -2,9 +2,15 @@
|
|||
#define SPARC_LD_OP(name, qp) \
|
||||
void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \
|
||||
{ \
|
||||
T1 = glue(qp, MEMSUFFIX)(T0); \
|
||||
T1 = (target_ulong)glue(qp, MEMSUFFIX)(T0); \
|
||||
}
|
||||
|
||||
#define SPARC_LD_OP_S(name, qp) \
|
||||
void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \
|
||||
{ \
|
||||
T1 = (target_long)glue(qp, MEMSUFFIX)(T0); \
|
||||
}
|
||||
|
||||
#define SPARC_ST_OP(name, op) \
|
||||
void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \
|
||||
{ \
|
||||
|
@ -14,8 +20,8 @@ void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \
|
|||
SPARC_LD_OP(ld, ldl);
|
||||
SPARC_LD_OP(ldub, ldub);
|
||||
SPARC_LD_OP(lduh, lduw);
|
||||
SPARC_LD_OP(ldsb, ldsb);
|
||||
SPARC_LD_OP(ldsh, ldsw);
|
||||
SPARC_LD_OP_S(ldsb, ldsb);
|
||||
SPARC_LD_OP_S(ldsh, ldsw);
|
||||
|
||||
/*** Integer store ***/
|
||||
SPARC_ST_OP(st, stl);
|
||||
|
@ -68,4 +74,51 @@ void OPPROTO glue(op_lddf, MEMSUFFIX) (void)
|
|||
{
|
||||
DT0 = glue(ldfq, MEMSUFFIX)(T0);
|
||||
}
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
/* XXX: Should be Atomically */
|
||||
/* XXX: There are no cas[x] instructions, only cas[x]a */
|
||||
void OPPROTO glue(op_cas, MEMSUFFIX)(void)
|
||||
{
|
||||
uint32_t tmp;
|
||||
|
||||
tmp = glue(ldl, MEMSUFFIX)(T0);
|
||||
T2 &= 0xffffffffULL;
|
||||
if (tmp == (T1 & 0xffffffffULL)) {
|
||||
glue(stl, MEMSUFFIX)(T0, T2);
|
||||
}
|
||||
T2 = tmp;
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_casx, MEMSUFFIX)(void)
|
||||
{
|
||||
uint64_t tmp;
|
||||
|
||||
// XXX
|
||||
tmp = (uint64_t)glue(ldl, MEMSUFFIX)(T0) << 32;
|
||||
tmp |= glue(ldl, MEMSUFFIX)(T0);
|
||||
if (tmp == T1) {
|
||||
glue(stq, MEMSUFFIX)(T0, T2);
|
||||
}
|
||||
T2 = tmp;
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_ldsw, MEMSUFFIX)(void)
|
||||
{
|
||||
T1 = (int64_t)glue(ldl, MEMSUFFIX)(T0);
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_ldx, MEMSUFFIX)(void)
|
||||
{
|
||||
// XXX
|
||||
T1 = (uint64_t)glue(ldl, MEMSUFFIX)(T0) << 32;
|
||||
T1 |= glue(ldl, MEMSUFFIX)(T0);
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_stx, MEMSUFFIX)(void)
|
||||
{
|
||||
glue(stl, MEMSUFFIX)(T0, T1 >> 32);
|
||||
glue(stl, MEMSUFFIX)(T0, T1 & 0xffffffff);
|
||||
}
|
||||
#endif
|
||||
#undef MEMSUFFIX
|
||||
|
|
File diff suppressed because it is too large
Load Diff
35
vl.c
35
vl.c
|
@ -2375,12 +2375,14 @@ void cpu_save(QEMUFile *f, void *opaque)
|
|||
qemu_put_betls(f, &env->y);
|
||||
tmp = GET_PSR(env);
|
||||
qemu_put_be32(f, tmp);
|
||||
qemu_put_be32s(f, &env->fsr);
|
||||
qemu_put_betls(f, &env->fsr);
|
||||
qemu_put_betls(f, &env->tbr);
|
||||
#ifndef TARGET_SPARC64
|
||||
qemu_put_be32s(f, &env->wim);
|
||||
qemu_put_be32s(f, &env->tbr);
|
||||
/* MMU */
|
||||
for(i = 0; i < 16; i++)
|
||||
qemu_put_be32s(f, &env->mmuregs[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
int cpu_load(QEMUFile *f, void *opaque, int version_id)
|
||||
|
@ -2411,13 +2413,14 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
|
|||
env->cwp = 0; /* needed to ensure that the wrapping registers are
|
||||
correctly updated */
|
||||
PUT_PSR(env, tmp);
|
||||
qemu_get_be32s(f, &env->fsr);
|
||||
qemu_get_betls(f, &env->fsr);
|
||||
qemu_get_betls(f, &env->tbr);
|
||||
#ifndef TARGET_SPARC64
|
||||
qemu_get_be32s(f, &env->wim);
|
||||
qemu_get_be32s(f, &env->tbr);
|
||||
/* MMU */
|
||||
for(i = 0; i < 16; i++)
|
||||
qemu_get_be32s(f, &env->mmuregs[i]);
|
||||
|
||||
#endif
|
||||
tlb_flush(env, 1);
|
||||
return 0;
|
||||
}
|
||||
|
@ -2577,6 +2580,7 @@ typedef struct QEMUResetEntry {
|
|||
static QEMUResetEntry *first_reset_entry;
|
||||
static int reset_requested;
|
||||
static int shutdown_requested;
|
||||
static int powerdown_requested;
|
||||
|
||||
void qemu_register_reset(QEMUResetHandler *func, void *opaque)
|
||||
{
|
||||
|
@ -2614,6 +2618,12 @@ void qemu_system_shutdown_request(void)
|
|||
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
|
||||
}
|
||||
|
||||
void qemu_system_powerdown_request(void)
|
||||
{
|
||||
powerdown_requested = 1;
|
||||
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
|
||||
}
|
||||
|
||||
static void main_cpu_reset(void *opaque)
|
||||
{
|
||||
#if defined(TARGET_I386) || defined(TARGET_SPARC)
|
||||
|
@ -2728,20 +2738,25 @@ int main_loop(void)
|
|||
if (vm_running) {
|
||||
ret = cpu_exec(env);
|
||||
if (shutdown_requested) {
|
||||
ret = EXCP_INTERRUPT;
|
||||
ret = EXCP_INTERRUPT;
|
||||
break;
|
||||
}
|
||||
if (reset_requested) {
|
||||
reset_requested = 0;
|
||||
qemu_system_reset();
|
||||
ret = EXCP_INTERRUPT;
|
||||
ret = EXCP_INTERRUPT;
|
||||
}
|
||||
if (powerdown_requested) {
|
||||
powerdown_requested = 0;
|
||||
qemu_system_powerdown();
|
||||
ret = EXCP_INTERRUPT;
|
||||
}
|
||||
if (ret == EXCP_DEBUG) {
|
||||
vm_stop(EXCP_DEBUG);
|
||||
}
|
||||
/* if hlt instruction, we wait until the next IRQ */
|
||||
/* XXX: use timeout computed from timers */
|
||||
if (ret == EXCP_HLT)
|
||||
if (ret == EXCP_HLT)
|
||||
timeout = 10;
|
||||
else
|
||||
timeout = 0;
|
||||
|
@ -3044,8 +3059,12 @@ void register_machines(void)
|
|||
qemu_register_machine(&core99_machine);
|
||||
qemu_register_machine(&prep_machine);
|
||||
#elif defined(TARGET_SPARC)
|
||||
#ifdef TARGET_SPARC64
|
||||
qemu_register_machine(&sun4u_machine);
|
||||
#else
|
||||
qemu_register_machine(&sun4m_machine);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#define NET_IF_TUN 0
|
||||
|
|
14
vl.h
14
vl.h
|
@ -110,6 +110,13 @@ typedef void QEMUResetHandler(void *opaque);
|
|||
void qemu_register_reset(QEMUResetHandler *func, void *opaque);
|
||||
void qemu_system_reset_request(void);
|
||||
void qemu_system_shutdown_request(void);
|
||||
void qemu_system_powerdown_request(void);
|
||||
#if !defined(TARGET_SPARC)
|
||||
// Please implement a power failure function to signal the OS
|
||||
#define qemu_system_powerdown() do{}while(0)
|
||||
#else
|
||||
void qemu_system_powerdown(void);
|
||||
#endif
|
||||
|
||||
void main_loop_wait(int timeout);
|
||||
|
||||
|
@ -753,9 +760,16 @@ void slavio_timer_init(uint32_t addr1, int irq1, uint32_t addr2, int irq2);
|
|||
SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2);
|
||||
void slavio_serial_ms_kbd_init(int base, int irq);
|
||||
|
||||
/* slavio_misc.c */
|
||||
void *slavio_misc_init(uint32_t base, int irq);
|
||||
void slavio_set_power_fail(void *opaque, int power_failing);
|
||||
|
||||
/* esp.c */
|
||||
void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr);
|
||||
|
||||
/* sun4u.c */
|
||||
extern QEMUMachine sun4u_machine;
|
||||
|
||||
/* NVRAM helpers */
|
||||
#include "hw/m48t59.h"
|
||||
|
||||
|
|
Loading…
Reference in New Issue