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:
bellard 2005-07-02 14:31:34 +00:00
parent 8979b2277d
commit 3475187dd8
26 changed files with 3651 additions and 637 deletions

View File

@ -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:

View File

@ -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)

View File

@ -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;
}

View File

@ -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;

View File

@ -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)

218
hw/elf_ops.h Normal file
View File

@ -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;
}

View File

@ -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;

View File

@ -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)

240
hw/slavio_misc.c Normal file
View File

@ -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;
}

View File

@ -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;

254
hw/sun4u.c Normal file
View File

@ -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,
};

View File

@ -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:

View File

@ -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, },

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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 *)&REG;
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 *)&REG;
u.d = DT2;
*(p +1) = u.l.lower;
*p = u.l.upper;
}
#undef REG
#undef REGNAME

View File

@ -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

View File

@ -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

View File

@ -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
View File

@ -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
View File

@ -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"