diff options
Diffstat (limited to 'roms/openbios/arch/sparc32')
32 files changed, 6368 insertions, 0 deletions
diff --git a/roms/openbios/arch/sparc32/boot.c b/roms/openbios/arch/sparc32/boot.c new file mode 100644 index 00000000..49ec4cfb --- /dev/null +++ b/roms/openbios/arch/sparc32/boot.c @@ -0,0 +1,261 @@ +/* + * + */ +#undef BOOTSTRAP +#include "config.h" +#include "libopenbios/bindings.h" +#include "arch/common/nvram.h" +#include "drivers/drivers.h" +#include "libc/diskio.h" +#include "libc/vsprintf.h" +#include "libopenbios/ofmem.h" +#include "libopenbios/sys_info.h" +#include "openprom.h" +#include "boot.h" +#include "context.h" + +uint32_t kernel_image; +uint32_t kernel_size; +uint32_t qemu_cmdline; +uint32_t cmdline_size; +char boot_device; +const void *romvec; + +static struct linux_mlist_v0 *totphyslist, *availlist, *prommaplist; + +static void setup_romvec(void) +{ +	/* SPARC32 is slightly unusual in that before invoking any loaders, a romvec array +	   needs to be set up to pass certain parameters using a C struct. Hence this function +	   extracts the relevant boot information and places it in obp_arg. */ + +	int intprop, proplen, target, device, i; +	unsigned int *intprop_ptr; +	phandle_t chosen; +	char *prop, *id, *name; +	static char bootpathbuf[128], bootargsbuf[128], buf[128]; +	struct linux_mlist_v0 **pp; + +	/* Get the stdin and stdout paths */ +	chosen = find_dev("/chosen"); +	intprop = get_int_property(chosen, "stdin", &proplen); +	PUSH(intprop); +	fword("get-instance-path"); +	((struct linux_romvec *)romvec)->pv_stdin = pop_fstr_copy(); + +	intprop = get_int_property(chosen, "stdout", &proplen); +	PUSH(intprop); +	fword("get-instance-path"); +	((struct linux_romvec *)romvec)->pv_stdout = pop_fstr_copy(); + +	/* Get the name of the selected boot device, along with the device and unit number */ +	prop = get_property(chosen, "bootpath", &proplen); +	strncpy(bootpathbuf, prop, proplen); +	prop = get_property(chosen, "bootargs", &proplen); +	strncpy(bootargsbuf, prop, proplen);	 + +	/* Set bootpath pointer used in romvec table to the bootpath */ +        push_str(bootpathbuf); +        fword("pathres-resolve-aliases"); +        bootpath = pop_fstr_copy(); +        printk("bootpath: %s\n", bootpath); + +	/* Now do some work to get hold of the target, partition etc. */ +	push_str(bootpathbuf); +	feval("open-dev"); +	feval("ihandle>boot-device-handle drop to my-self"); +	push_str("name"); +	fword("get-my-property"); +	POP(); +	name = pop_fstr_copy(); + +        if (!strncmp(name, "sd", 2)) { + +		/* +		  Old-style SunOS disk paths are given in the form: + +			sd(c,t,d):s + +		  where: +		    c = controller (Nth controller in system, usually 0) +		    t = target (my-unit phys.hi) +		    d = device/LUN (my-unit phys.lo) +		    s = slice/partition (my-args) +		*/ + +		/* Controller currently always 0 */ +		obp_arg.boot_dev_ctrl = 0; + +		/* Get the target, device and slice */ +		fword("my-unit"); +		target = POP(); +		device = POP(); + +		fword("my-args"); +		id = pop_fstr_copy(); + +		if (id != NULL) { +			snprintf(buf, sizeof(buf), "sd(0,%d,%d):%c", target, device, id[0]); +			obp_arg.dev_partition = id[0] - 'a'; +		} else { +			snprintf(buf, sizeof(buf), "sd(0,%d,%d)", target, device); +			obp_arg.dev_partition = 0; +		} + +		obp_arg.boot_dev_unit = target; + +		obp_arg.boot_dev[0] = buf[0]; +		obp_arg.boot_dev[1] = buf[1]; +		obp_arg.argv[0] = buf; +        	obp_arg.argv[1] = bootargsbuf; + +        } else if (!strncmp(name, "SUNW,fdtwo", 10)) { +		 +		obp_arg.boot_dev_ctrl = 0; +		obp_arg.boot_dev_unit = 0; +		obp_arg.dev_partition = 0; + +		strcpy(buf, "fd()"); + +		obp_arg.boot_dev[0] = buf[0]; +		obp_arg.boot_dev[1] = buf[1]; +		obp_arg.argv[0] = buf; +        	obp_arg.argv[1] = bootargsbuf; + +        } else if (!strncmp(name, "le", 2)) { + +		obp_arg.boot_dev_ctrl = 0; +		obp_arg.boot_dev_unit = 0; +		obp_arg.dev_partition = 0; + +		strcpy(buf, "le()"); + +		obp_arg.boot_dev[0] = buf[0]; +		obp_arg.boot_dev[1] = buf[1]; +		obp_arg.argv[0] = buf; +        	obp_arg.argv[1] = bootargsbuf; + +	} + +	/* Generate the totphys (total memory available) list */ +	prop = get_property(s_phandle_memory, "reg", &proplen); +	intprop_ptr = (unsigned int *)prop; + +	for (pp = &totphyslist, i = 0; i < (proplen / sizeof(int)); pp = &(**pp).theres_more, i+=3) { +		*pp = (struct linux_mlist_v0 *)malloc(sizeof(struct linux_mlist_v0)); +		(**pp).theres_more = NULL; +		(**pp).start_adr = (char *)intprop_ptr[1]; +		(**pp).num_bytes = intprop_ptr[2]; + +		intprop_ptr += 3; +	} + +	/* Generate the avail (physical memory available) list */ +	prop = get_property(s_phandle_memory, "available", &proplen); +	intprop_ptr = (unsigned int *)prop; + +	for (pp = &availlist, i = 0; i < (proplen / sizeof(int)); pp = &(**pp).theres_more, i+=3) { +		*pp = (struct linux_mlist_v0 *)malloc(sizeof(struct linux_mlist_v0)); +		(**pp).theres_more = NULL; +		(**pp).start_adr = (char *)intprop_ptr[1]; +		(**pp).num_bytes = intprop_ptr[2]; + +		intprop_ptr += 3; +	} + +	/* Generate the prommap (taken virtual memory) list from inverse of available */ +	prop = get_property(s_phandle_mmu, "available", &proplen); +	intprop_ptr = (unsigned int *)prop; + +	for (pp = &prommaplist, i = 0; i < (proplen / sizeof(int)); pp = &(**pp).theres_more, i+=3) { +		*pp = (struct linux_mlist_v0 *)malloc(sizeof(struct linux_mlist_v0)); +		(**pp).theres_more = NULL; +		(**pp).start_adr = (char *)(intprop_ptr[1] + intprop_ptr[2]); + +		if (i + 3 < (proplen / sizeof(int))) { +			/* Size from next entry */ +			(**pp).num_bytes = (intprop_ptr[4] + intprop_ptr[5]) - (intprop_ptr[1] + intprop_ptr[2]); +		} else { +			/* Tail (size from top of virtual memory) */ +			(**pp).num_bytes = 0xffffffffUL - (intprop_ptr[1] + intprop_ptr[2]) + 1; +		} + +		intprop_ptr += 3; +	} + +	/* Finally set the memory properties */ +	((struct linux_romvec *)romvec)->pv_v0mem.v0_totphys = &totphyslist; +	((struct linux_romvec *)romvec)->pv_v0mem.v0_available = &availlist; +	((struct linux_romvec *)romvec)->pv_v0mem.v0_prommap = &prommaplist; +} + + +void go(void) +{ +	ucell address, type, size; +	int image_retval = 0; + +	/* Get the entry point and the type (see forth/debugging/client.fs) */ +	feval("saved-program-state >sps.entry @"); +	address = POP(); +	feval("saved-program-state >sps.file-type @"); +	type = POP(); +	feval("saved-program-state >sps.file-size @"); +	size = POP(); + +	setup_romvec(); + +	printk("\nJumping to entry point " FMT_ucellx " for type " FMT_ucellx "...\n", address, type); + +	switch (type) { +		case 0x0: +			/* Start ELF boot image */ +			image_retval = start_elf((unsigned long)address, +                                                 (unsigned long)romvec); + +			break; + +		case 0x1: +			/* Start ELF image */ +			image_retval = start_elf((unsigned long)address, +                                                 (unsigned long)romvec); + +			break; + +		case 0x5: +			/* Start a.out image */ +			image_retval = start_elf((unsigned long)address, +                                                 (unsigned long)romvec); + +			break; + +		case 0x10: +			/* Start Fcode image */ +			printk("Evaluating FCode...\n"); +			PUSH(address); +			PUSH(1); +			fword("byte-load"); +			image_retval = 0; +			break; + +		case 0x11: +			/* Start Forth image */ +			PUSH(address); +			PUSH(size); +			fword("eval2"); +			image_retval = 0; +			break; +	} + +	printk("Image returned with return value %#x\n", image_retval); +} + + +void boot(void) +{ +	/* Boot preloaded kernel */ +        if (kernel_size) { +            printk("[sparc] Kernel already loaded\n"); +            start_elf(kernel_image, (unsigned long)romvec); +        } +} diff --git a/roms/openbios/arch/sparc32/boot.h b/roms/openbios/arch/sparc32/boot.h new file mode 100644 index 00000000..55e391ac --- /dev/null +++ b/roms/openbios/arch/sparc32/boot.h @@ -0,0 +1,41 @@ +/* tag: openbios loader prototypes for sparc32 + * + * Copyright (C) 2004 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +// linux_load.c +int linux_load(struct sys_info *info, const char *file, const char *cmdline); + +// context.c +extern struct context *__context; +unsigned int start_elf(unsigned long entry_point, unsigned long param); + +// boot.c +extern const char *bootpath; +extern void boot(void); +extern void go(void); + +// sys_info.c +extern unsigned int qemu_mem_size; +extern void collect_sys_info(struct sys_info *info); + +// romvec.c +extern struct linux_arguments_v0 obp_arg; +extern const void *romvec; +extern const char *obp_stdin_path, *obp_stdout_path; +extern char obp_stdin, obp_stdout; + +// openbios.c +extern int qemu_machine_type; + +// arch/sparc32/lib.c +struct linux_mlist_v0; +extern struct linux_mlist_v0 *ptphys; +extern struct linux_mlist_v0 *ptmap; +extern struct linux_mlist_v0 *ptavail; + +void ob_init_mmu(void); +void init_mmu_swift(void); diff --git a/roms/openbios/arch/sparc32/build.xml b/roms/openbios/arch/sparc32/build.xml new file mode 100644 index 00000000..81c3586e --- /dev/null +++ b/roms/openbios/arch/sparc32/build.xml @@ -0,0 +1,74 @@ +<build condition="SPARC32"> + + <dictionary name="openbios-sparc32" init="openbios"> +  <object source="tree.fs" target="forth"/> +  <object source="init.fs" target="forth"/> +  <object source="QEMU,tcx.bin" target="fcode" condition="DRIVER_SBUS"/> +  <object source="QEMU,cgthree.bin" target="fcode" condition="DRIVER_SBUS"/> + </dictionary> + + <library name="sparc32" type="static" target="target"> +  <object source="openbios.c"/> +  <object source="console.c"/> +  <object source="lib.c"/> +  <object source="boot.c"/> +  <object source="context.c"/> +  <object source="switch.S"/> +  <object source="udiv.S"/> +  <object source="linux_load.c"/> +  <object source="sys_info.c"/> +  <object source="ofmem_sparc32.c"/> +  <object source="romvec.c"/> +  <object source="call-romvec.S"/> +  <object source="entry.S"/> +  <object source="vectors.S"/> + </library> + + <executable name="openbios-plain.elf" target="target" condition="IMAGE_ELF"> +  <rule> +	$(call quiet-command,$(LD) --warn-common -N -T $(SRCDIR)/arch/sparc32/ldscript -o $@.nostrip --whole-archive $^,"  LINK  $(TARGET_DIR)$@") +	$(call quiet-command,$(NM) $@.nostrip | sort > $(ODIR)/openbios-plain.syms,"  GEN   $(TARGET_DIR)$@.syms") +	$(call quiet-command,$(STRIP) $@.nostrip -o $@,"  STRIP $(TARGET_DIR)$@")</rule> +  <object source="plainboot.c"/> +  <external-object source="libsparc32.a"/> +  <external-object source="libbootstrap.a"/> +  <external-object source="libopenbios.a"/> +  <external-object source="libpackages.a"/> +  <external-object source="libdrivers.a"/> +  <external-object source="libfs.a"/> +  <external-object source="liblibc.a"/> +  <external-object source="libgcc.a"/> + </executable> + + <!-- HACK ALERT --> + + <executable name="target/include/static-dict.h" target="target" condition="IMAGE_ELF_EMBEDDED"> +  <rule><![CDATA[ +	$(call quiet-command,$(ODIR)/forthstrap -x -D $@ -d $< </dev/null, "  GEN   $(TARGET_DIR)$@")]]></rule> +  <external-object source="openbios-sparc32.dict"/> + </executable> + + <executable name="target/arch/sparc32/builtin.o" target="target" condition="IMAGE_ELF_EMBEDDED"> +  <rule><![CDATA[ $(SRCDIR)/arch/sparc32/builtin.c $(ODIR)/target/include/static-dict.h +	$(call quiet-command,$(CC) $$EXTRACFLAGS $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/arch/sparc32/builtin.c, "  CC    $(TARGET_DIR)$@")]]></rule> + </executable> + + <!-- END OF HACK ALERT --> + + <executable name="openbios-builtin.elf" target="target" condition="IMAGE_ELF_EMBEDDED"> +  <rule> +	$(call quiet-command,$(LD) --warn-common -N -T $(SRCDIR)/arch/sparc32/ldscript -o $@.nostrip --whole-archive $^,"  LINK  $(TARGET_DIR)$@") +	$(call quiet-command,$(NM) $@.nostrip | sort > $(ODIR)/openbios-builtin.syms,"  GEN   $(TARGET_DIR)$@.syms") +	$(call quiet-command,$(STRIP) $@.nostrip -o $@,"  STRIP $(TARGET_DIR)$@")</rule> +  <external-object source="target/arch/sparc32/builtin.o"/> +  <external-object source="libsparc32.a"/> +  <external-object source="libbootstrap.a"/> +  <external-object source="libopenbios.a"/> +  <external-object source="libpackages.a"/> +  <external-object source="libdrivers.a"/> +  <external-object source="libfs.a"/> +  <external-object source="liblibc.a"/> +  <external-object source="libgcc.a"/> + </executable> + +</build> diff --git a/roms/openbios/arch/sparc32/builtin.c b/roms/openbios/arch/sparc32/builtin.c new file mode 100644 index 00000000..971a4009 --- /dev/null +++ b/roms/openbios/arch/sparc32/builtin.c @@ -0,0 +1,33 @@ +/* tag: openbios forth starter for builtin dictionary for sparc32 + * + * Copyright (C) 2003 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#include "config.h" +#include "asm/types.h" +#include "libopenbios/sys_info.h" + +/* + * wrap an array around the hex'ed dictionary file + */ + +/* 256K for the dictionary */ +#define DICTIONARY_SIZE (256 * 1024 / sizeof(ucell)) +#define DICTIONARY_BASE ((ucell)((char *)&forth_dictionary)) + +static ucell forth_dictionary[DICTIONARY_SIZE] = { +#include "static-dict.h" +}; + +void collect_multiboot_info(struct sys_info *info); +void collect_multiboot_info(struct sys_info *info) +{ +	info->dict_start=(unsigned long *)forth_dictionary; +        info->dict_end = (unsigned long *)FORTH_DICTIONARY_END; +        info->dict_last = (ucell *)((unsigned char *)forth_dictionary + +                                            FORTH_DICTIONARY_LAST); +        info->dict_limit = sizeof(forth_dictionary); +} diff --git a/roms/openbios/arch/sparc32/call-romvec.S b/roms/openbios/arch/sparc32/call-romvec.S new file mode 100644 index 00000000..be77b232 --- /dev/null +++ b/roms/openbios/arch/sparc32/call-romvec.S @@ -0,0 +1,94 @@ +#define __ASSEMBLY +#include "psr.h" +#include "asm/asi.h" + +	.text +	.align	4 + +#define STACKFRAME_SZ     0x60 + +/* These are just handy. */ +#define _SV	save	%sp, -STACKFRAME_SZ, %sp +#define _RS     restore + +#define FLUSH_ALL_KERNEL_WINDOWS \ +	_SV; _SV; _SV; _SV; _SV; _SV; _SV; \ +	_RS; _RS; _RS; _RS; _RS; _RS; _RS; + +/* Macro for romvec handlers */ +#define ROMVEC_HANDLER(type) \ +	\ +	.globl type##_handler; \ +	\ +type##_handler: \ +	\ +	FLUSH_ALL_KERNEL_WINDOWS; \ +	\ +	save %sp, -STACKFRAME_SZ - 0x20, %sp; \ +	\ +	st %g1, [ %sp + STACKFRAME_SZ + 0x0]; \ +	st %g2, [ %sp + STACKFRAME_SZ + 0x4]; \ +	st %g3, [ %sp + STACKFRAME_SZ + 0x8]; \ +	st %g4, [ %sp + STACKFRAME_SZ + 0xc]; \ +	st %g5, [ %sp + STACKFRAME_SZ + 0x10]; \ +	st %g6, [ %sp + STACKFRAME_SZ + 0x14]; \ +	st %g7, [ %sp + STACKFRAME_SZ + 0x18]; \ +	\ +	mov %i0, %o0; \ +	mov %i1, %o1; \ +	mov %i2, %o2; \ +	mov %i3, %o3; \ +	mov %i4, %o4; \ +	mov %i5, %o5; \ +	\ +	call	type; \ +	 nop; \ +	\ +	mov %o0, %i0; \ +	\ +	ld [ %sp + STACKFRAME_SZ + 0x0], %g1; \ +	ld [ %sp + STACKFRAME_SZ + 0x4], %g2; \ +	ld [ %sp + STACKFRAME_SZ + 0x8], %g3; \ +	ld [ %sp + STACKFRAME_SZ + 0xc], %g4; \ +	ld [ %sp + STACKFRAME_SZ + 0x10], %g5; \ +	ld [ %sp + STACKFRAME_SZ + 0x14], %g6; \ +	ld [ %sp + STACKFRAME_SZ + 0x18], %g7; \ +	\ +	ret; \ +	 restore; \ + + +/* Generate handlers which are proxy functions to the  +   real C functions that correctly save the globals +   and stack */ +ROMVEC_HANDLER(obp_devopen) +ROMVEC_HANDLER(obp_devclose) +ROMVEC_HANDLER(obp_rdblkdev) +ROMVEC_HANDLER(obp_nbgetchar) +ROMVEC_HANDLER(obp_nbputchar) +ROMVEC_HANDLER(obp_putstr) +ROMVEC_HANDLER(obp_printf) +ROMVEC_HANDLER(obp_reboot) +ROMVEC_HANDLER(obp_abort) +ROMVEC_HANDLER(obp_halt) +ROMVEC_HANDLER(obp_fortheval_v2) +ROMVEC_HANDLER(obp_inst2pkg) +ROMVEC_HANDLER(obp_dumb_memalloc) +ROMVEC_HANDLER(obp_dumb_memfree) +ROMVEC_HANDLER(obp_dumb_mmap) +ROMVEC_HANDLER(obp_dumb_munmap) +ROMVEC_HANDLER(obp_devread) +ROMVEC_HANDLER(obp_devwrite) +ROMVEC_HANDLER(obp_devseek) +ROMVEC_HANDLER(obp_cpustart) +ROMVEC_HANDLER(obp_cpustop) +ROMVEC_HANDLER(obp_cpuidle) +ROMVEC_HANDLER(obp_cpuresume) +ROMVEC_HANDLER(obp_nextnode) +ROMVEC_HANDLER(obp_child) +ROMVEC_HANDLER(obp_proplen) +ROMVEC_HANDLER(obp_getprop) +ROMVEC_HANDLER(obp_setprop) +ROMVEC_HANDLER(obp_nextprop) +ROMVEC_HANDLER(obp_memalloc) + diff --git a/roms/openbios/arch/sparc32/console.c b/roms/openbios/arch/sparc32/console.c new file mode 100644 index 00000000..61c2e238 --- /dev/null +++ b/roms/openbios/arch/sparc32/console.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2003, 2004 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#include "config.h" +#include "kernel/kernel.h" +#include "drivers/drivers.h" +#include "openbios.h" +#include "libopenbios/console.h" +#include "libopenbios/ofmem.h" +#include "libopenbios/video.h" + +#ifdef CONFIG_DEBUG_CONSOLE + +/* ****************************************************************** + *      common functions, implementing simple concurrent console + * ****************************************************************** */ + +static int arch_putchar(int c) +{ +#ifdef CONFIG_DEBUG_CONSOLE_SERIAL +	escc_uart_putchar(c); +#endif +	return c; +} + +static int arch_availchar(void) +{ +#ifdef CONFIG_DEBUG_CONSOLE_SERIAL +	if (escc_uart_charav(CONFIG_SERIAL_PORT)) +		return 1; +#endif +#ifdef CONFIG_DEBUG_CONSOLE_VIDEO +	if (keyboard_dataready()) +		return 1; +#endif +	return 0; +} + +static int arch_getchar(void) +{ +#ifdef CONFIG_DEBUG_CONSOLE_SERIAL +	if (escc_uart_charav(CONFIG_SERIAL_PORT)) +		return (escc_uart_getchar(CONFIG_SERIAL_PORT)); +#endif +#ifdef CONFIG_DEBUG_CONSOLE_VIDEO +	if (keyboard_dataready()) +		return (keyboard_readdata()); +#endif +	return 0; +} + +struct _console_ops arch_console_ops = { +	.putchar = arch_putchar, +	.availchar = arch_availchar, +	.getchar = arch_getchar +}; + +#endif				// CONFIG_DEBUG_CONSOLE diff --git a/roms/openbios/arch/sparc32/context.c b/roms/openbios/arch/sparc32/context.c new file mode 100644 index 00000000..d4d8530d --- /dev/null +++ b/roms/openbios/arch/sparc32/context.c @@ -0,0 +1,113 @@ +/* + * context switching + * 2003-10 by SONE Takeshi + */ + +#include "config.h" +#include "kernel/kernel.h" +#include "context.h" +#include "libopenbios/sys_info.h" +#include "boot.h" +#include "openbios.h" + +#define MAIN_STACK_SIZE 16384 +#define IMAGE_STACK_SIZE 4096*2 + +#define debug printk + +static void start_main(void); /* forward decl. */ +void __exit_context(void); /* assembly routine */ + +/* + * Main context structure + * It is placed at the bottom of our stack, and loaded by assembly routine + * to start us up. + */ +static struct context main_ctx = { +    .regs[REG_SP] = (uint32_t) &_estack - 96, +    .pc = (uint32_t) start_main, +    .npc = (uint32_t) start_main + 4, +    .return_addr = (uint32_t) __exit_context, +}; + +/* This is used by assembly routine to load/store the context which + * it is to switch/switched.  */ +struct context *__context = &main_ctx; + +/* Stack for loaded ELF image */ +static uint8_t image_stack[IMAGE_STACK_SIZE]; + +/* Pointer to startup context (physical address) */ +unsigned long __boot_ctx; + +/* + * Main starter + * This is the C function that runs first. + */ +static void start_main(void) +{ +    /* Save startup context, so we can refer to it later. +     * We have to keep it in physical address since we will relocate. */ +    __boot_ctx = virt_to_phys(__context); + +    /* Start the real fun */ +    openbios(); + +    /* Returning from here should jump to __exit_context */ +    __context = boot_ctx; +} + +/* Setup a new context using the given stack. + */ +struct context * +init_context(uint8_t *stack, uint32_t stack_size, int num_params) +{ +    struct context *ctx; + +    ctx = (struct context *) +	(stack + stack_size - (sizeof(*ctx) + num_params*sizeof(uint32_t))); +    memset(ctx, 0, sizeof(*ctx)); + +    /* Fill in reasonable default for flat memory model */ +    ctx->regs[REG_SP] = virt_to_phys(SP_LOC(ctx)); +    ctx->return_addr = virt_to_phys(__exit_context); + +    return ctx; +} + +/* Switch to another context. */ +struct context *switch_to(struct context *ctx) +{ +    volatile struct context *save; +    struct context *ret; + +    debug("switching to new context:\n"); +    save = __context; +    __context = ctx; +    asm __volatile__ ("\n\tcall __switch_context" +                      "\n\tnop" ::: "g1", "g2", "g3", "g4", "g5", "g6", "g7", +                      "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7", +                      "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", +                      "i0", "i1", "i2", "i3", "i4", "i5", "i7", +                      "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", +                      "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", +                      "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", +                      "f30", "f31", +                      "memory"); +    ret = __context; +    __context = (struct context *)save; +    return ret; +} + +/* Start ELF Boot image */ +unsigned int start_elf(unsigned long entry_point, unsigned long param) +{ +    struct context *ctx; + +    ctx = init_context(image_stack, sizeof image_stack, 1); +    ctx->pc = entry_point; +    ctx->param[0] = param; + +    ctx = switch_to(ctx); +    return ctx->regs[REG_O0]; +} diff --git a/roms/openbios/arch/sparc32/context.h b/roms/openbios/arch/sparc32/context.h new file mode 100644 index 00000000..8689d563 --- /dev/null +++ b/roms/openbios/arch/sparc32/context.h @@ -0,0 +1,31 @@ +#ifndef SPARC32_CONTEXT_H +#define SPARC32_CONTEXT_H + +struct context { +    /* General registers */ +    uint32_t regs[32]; +    uint32_t pc; +    uint32_t npc; +#define REG_O0 8 +#define REG_SP 14 +#define SP_LOC(ctx) (&(ctx)->regs[REG_SP]) +    /* Flags */ +    /* Optional stack contents */ +    uint32_t return_addr; +    uint32_t param[0]; +}; + +/* Create a new context in the given stack */ +struct context * +init_context(uint8_t *stack, uint32_t stack_size, int num_param); + +/* Switch context */ +struct context *switch_to(struct context *); + +/* Holds physical address of boot context */ +extern unsigned long __boot_ctx; + +/* This can always be safely used to refer to the boot context */ +#define boot_ctx ((struct context *) phys_to_virt(__boot_ctx)) + +#endif /* SPARC32_CONTEXT_H */ diff --git a/roms/openbios/arch/sparc32/crs.h b/roms/openbios/arch/sparc32/crs.h new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/roms/openbios/arch/sparc32/crs.h diff --git a/roms/openbios/arch/sparc32/entry.S b/roms/openbios/arch/sparc32/entry.S new file mode 100644 index 00000000..72cb3386 --- /dev/null +++ b/roms/openbios/arch/sparc32/entry.S @@ -0,0 +1,532 @@ +/** + ** Standalone startup code for Linux PROM emulator. + ** Copyright 1999 Pete A. Zaitcev + ** This code is licensed under GNU General Public License. + **/ +/* + * $Id: head.S,v 1.12 2002/07/23 05:47:09 zaitcev Exp $ + */ + +#define __ASSEMBLY +#include "psr.h" +#include "asm/asi.h" +#include "asm/crs.h" +#define NO_QEMU_PROTOS +#define NO_OPENBIOS_PROTOS +#include "arch/common/fw_cfg.h" + +#define CFG_ADDR 0x00000510 +#define CFG_ASI  0x2d + +#define PHYS_JJ_INTR0	0x71E00000  /* CPU0 interrupt control registers */ + +#define PHYS_SS10_INTR0 	0xf1400000 + +#define PHYS_SS2_INTR0 	0xf5000000 +#define SER_ADDR2       0xf1000004 + +#define PHYS_SS1000_SBI         0x02800000 +#define SER_ADDR1000            0x00200004 + +#define WRITE_PAUSE    nop; nop; nop; /* Have to do this after %wim/%psr chg */ + +        .globl	entry, _entry + +	.section ".text", "ax" +	.align	8 + +        /* Memory map: +	 * +	 * Top +-------------------------+ +	 *     | SMP CPU table           | +	 *     | s + 0x1f00 ... 0x1f0f   | +	 *     | s + 0x1f0c valid        | +	 *     | s + 0x1f08 entry        | +	 *     | s + 0x1f04 ctxtbl       | +	 *     | s + 0x1f00 ctx          | +	 *     +-------------------------+ +	 *     | Bootstrap               | +	 *     | MMU L3 tables 8 * 0x100 | +	 *     | s + 0xa00 ... 0x11ff    | +	 *     +-------------------------+ +	 *     | Bootstrap               | +	 *     | MMU L2 tables 2 * 0x100 | +	 *     | s + 0x800 ... 0x9ff     | +	 *     +-------------------------+ +	 *     | Bootstrap               | +	 *     | MMU L1 table 0x400      | +	 *     | s + 0x400 ... 0x7ff     | +	 *     +-------------------------+ +	 *     | Bootstrap               | +	 *     | MMU L0/ctx table 0x400  | +	 *     | s + 0x000 ... 0x3ff     | +	 *     +-------------------------+ +	 *     |                         | +	 *     | ROM into RAM            | +	 *     |                         | +	 *     +-------------------------+ +	 *     :                         : +	 * Bottom +	 */ + +/* + * Entry point + * We start execution from here. + */ +_entry: +entry: +        /* Switch to our main context. +         * Main context is statically defined in C. +         */ + +        ! Check signature "QEMU" +        set     CFG_ADDR, %g5 +        mov     FW_CFG_SIGNATURE, %g2 +        stha    %g2, [%g5] CFG_ASI +        add     %g5, 2, %g5 +        lduba   [%g5] CFG_ASI, %g2 +        cmp     %g2, 'Q' +        bne     bad_conf +         nop +        lduba   [%g5] CFG_ASI, %g2 +        cmp     %g2, 'E' +        bne     bad_conf +         nop +        lduba   [%g5] CFG_ASI, %g2 +        cmp     %g2, 'M' +        bne     bad_conf +         nop +        lduba   [%g5] CFG_ASI, %g2 +        cmp     %g2, 'U' +        bne     bad_conf +         nop + +        ! Get memory size from configuration device +        ! NB: little endian format +        mov     FW_CFG_RAM_SIZE, %g2 +        sub     %g5, 2, %g5 +        stha    %g2, [%g5] CFG_ASI +        add     %g5, 2, %g5 +        lduba   [%g5] CFG_ASI, %g4 + +        lduba   [%g5] CFG_ASI, %g3 +        sll     %g3, 8, %g3 +        or      %g3, %g4, %g4 + +        lduba   [%g5] CFG_ASI, %g3 +        sll     %g3, 16, %g3 +        or      %g3, %g4, %g4 + +        lduba   [%g5] CFG_ASI, %g3 +        sll     %g3, 24, %g3 +        or      %g3, %g4, %g1 +        ! %g1 contains end of memory + +        ! Get kernel address from configuration device +        ! NB: little endian format +        mov     FW_CFG_KERNEL_ADDR, %g2 +        sub     %g5, 2, %g5 +        stha    %g2, [%g5] CFG_ASI +        add     %g5, 2, %g5 +        lduba   [%g5] CFG_ASI, %g4 + +        lduba   [%g5] CFG_ASI, %g3 +        sll     %g3, 8, %g3 +        or      %g3, %g4, %g4 + +        lduba   [%g5] CFG_ASI, %g3 +        sll     %g3, 16, %g3 +        or      %g3, %g4, %g4 + +        lduba   [%g5] CFG_ASI, %g3 +        sll     %g3, 24, %g3 +        or      %g3, %g4, %g4 + +        ! If kernel address is set, don't clear from base of RAM in order to +        ! leave the kernel image intact +        mov     0, %g6 +        cmp     %g4, 0 +        beq     clear_mem +         nop + +        ! Start from 16M +        set     0x1000000, %g6 + +clear_mem: +        sta     %g0, [%g6] ASI_M_BYPASS +        add     %g6, 0x4, %g6 +        cmp     %g6, %g1 +        bl      clear_mem +         nop + +clear_done: +        ! Start of private memory in %g6 +        set     0x2000, %g3 +        sub     %g1, %g3, %g6 + +        ! Check if this is the boot CPU and skip SMP table check if yes +        ! XXX: not all CPUs should have MXCC +        set     0x1c00f00, %g2 +        ldda    [%g2] ASI_CONTROL, %g2 +        srl     %g3, 24, %g7 +        sub     %g7, 8, %g7 +        tst     %g7 +        bz      skip_table +         nop + +        ! Calculate SMP table location +	set	0x1f0c, %g2 +        add     %g6, %g2, %g2                 ! valid? +        lda     [%g2] ASI_M_BYPASS, %g7 +        sta     %g0, [%g2] ASI_M_BYPASS + +skip_table: +        ! Get machine ID from configuration device +        mov     FW_CFG_MACHINE_ID, %g2 +        sub     %g5, 2, %g5 +        stha    %g2, [%g5] CFG_ASI +        add     %g5, 2, %g5 +        lduba   [%g5] CFG_ASI, %g4 + +        lduba   [%g5] CFG_ASI, %g3 +        sll     %g3, 8, %g3 +        or      %g3, %g4, %g4 +        mov     %g4, %y + +        cmp     %g4, 96 +        bgeu    ss1000 +         cmp    %g4, 64 +        bgeu    ss10 +         cmp    %g4, 32 +        blu     ss2 +         nop + +        ! Ok, this is SS-5 + +        tst     %g7 +        bz      first_cpu +         nop + +        ! Clear softints used for SMP CPU startup +        set     PHYS_JJ_INTR0 + 0x04, %g1 +        sll     %g2, 12, %g2 +        add     %g1, %g2, %g2 +        set     0xffffffff, %g1 +        sta     %g1, [%g2] ASI_M_BYPASS         ! clear softints +        add     %g2, 4, %g2 +        sta     %g0, [%g2] ASI_M_BYPASS         ! clear softints + +load_ctx: +        ! SMP init, jump to user specified address +	set	0x1f04, %g5 +        add     %g6, %g5, %g5                 ! ctxtbl +        lda     [%g5] ASI_M_BYPASS, %g2 +        sta     %g0, [%g5] ASI_M_BYPASS +        set     AC_M_CTPR, %g1 +        sta     %g2, [%g1] ASI_M_MMUREGS        ! set ctx table ptr +	set	0x1f00, %g5 +        add     %g6, %g5, %g5                 ! ctx +        lda     [%g5] ASI_M_BYPASS, %g2 +        sta     %g0, [%g5] ASI_M_BYPASS +        set     AC_M_CXR, %g1 +        sta     %g2, [%g1] ASI_M_MMUREGS        ! set context +	set	0x1f08, %g5 +        add     %g6, %g5, %g5                 ! entry +        lda     [%g5] ASI_M_BYPASS, %g2 +        sta     %g0, [%g5] ASI_M_BYPASS +        set     1, %g1 +        jmp     %g2                             ! jump to kernel +         sta    %g1, [%g0] ASI_M_MMUREGS        ! enable mmu + +ss10: +        ! Ok, this is SS-10 or SS-600MP +        tst     %g7 +        bz      first_cpu +         nop + +        ! Clear softints used for SMP CPU startup +        set     PHYS_SS10_INTR0 + 0x04, %g1 +        sll     %g2, 12, %g2 +        add     %g1, %g2, %g2 +        set     0xffffffff, %g1 +        sta     %g1, [%g2] ASI_M_CTL            ! clear softints +        add     %g2, 4, %g2 +        b       load_ctx +         sta    %g0, [%g2] ASI_M_CTL            ! clear softints + +ss2: +        ! Ok, this is SS-2 +        set     ss2_error, %o2 +        b       ss2_ss1000_halt +         nop + +ss1000: +        ! Ok, this is SS-1000 or SS-2000 +        set     ss1000_error, %o2 +        b       ss2_ss1000_halt +         nop + +first_cpu: +        /* Create temporary page tables and map the ROM area to end of +	RAM. This will be done properly in iommu.c later. */ +        ! Calculate start of page tables etc. to %g6 +        set     0x2000, %g4 +        sub     %g1, %g4, %g6                   ! start of private memory + +        mov     %g6, %g2                        ! ctx table at s+0x0 +        add	%g2, 0x400, %g3			! l1 table at s+0x400 +        srl	%g3, 0x4, %g3 +        or	%g3, 0x1, %g3 +        sta	%g3, [%g2] ASI_M_BYPASS +        add	%g2, 0x400, %g2			! s+0x400 +        add	%g2, 0x400, %g3			! l2 table for ram (00xxxxxx) at s+0x800 +        srl	%g3, 0x4, %g3 +        or	%g3, 0x1, %g3 +        sta	%g3, [%g2] ASI_M_BYPASS +        add	%g2, 0x500, %g3			! l2 table for rom (ffxxxxxx) at s+0x900 +        add	%g2, 0x3fc, %g2			! s+0x7fc +        srl	%g3, 0x4, %g3 +        or	%g3, 0x1, %g3 +        sta	%g3, [%g2] ASI_M_BYPASS +        add	%g2, 0x4, %g2			! s+0x800 +#if 0 +        set     0x40, %g6 +        set	((7 << 2) | 2), %g3		! 7 = U: --- S: RWX (main memory) +1:      sta	%g3, [%g2] ASI_M_BYPASS +        add     %g2, 4, %g2 +        deccc   %g6 +        bne     1b +         nop +#else +        add     %g2, 0x100, %g2 +#endif +                                                ! s+0x900 +        add	%g2, 0xa00 - 0x900, %g3		! l3 table for rom at s+0xa00 +        add	%g2, 0x0d0, %g2			! s+0x9d0 +        srl	%g3, 0x4, %g3 +        or	%g3, 0x1, %g3 +        sta	%g3, [%g2] ASI_M_BYPASS +        add	%g2, 4, %g2			! s+0x9d4 +        add	%g2, 0xb00 - 0x9d4, %g3		! 2nd l3 table for rom at s+0xb00 +        srl	%g3, 0x4, %g3 +        or	%g3, 0x1, %g3 +        sta	%g3, [%g2] ASI_M_BYPASS +        add	%g2, 4, %g2			! s+0x9d8 +        add	%g2, 0xc00 - 0x9d8, %g3		! 3rd l3 table for rom at s+0xc00 +        srl	%g3, 0x4, %g3 +        or	%g3, 0x1, %g3 +        sta	%g3, [%g2] ASI_M_BYPASS +        add	%g2, 4, %g2			! s+0x9dc +        add	%g2, 0xd00 - 0x9dc, %g3		! 4th l3 table for rom at s+0xd00 +        srl	%g3, 0x4, %g3 +        or	%g3, 0x1, %g3 +        sta	%g3, [%g2] ASI_M_BYPASS +        add	%g2, 4, %g2			! s+0x9e0 +        add	%g2, 0xe00 - 0x9e0, %g3		! 5th l3 table for rom at s+0xe00 +        srl	%g3, 0x4, %g3 +        or	%g3, 0x1, %g3 +        sta	%g3, [%g2] ASI_M_BYPASS +        add	%g2, 4, %g2			! s+0x9e4 +        add	%g2, 0xf00 - 0x9e4, %g3		! 6th l3 table for rom at s+0xf00 +        srl	%g3, 0x4, %g3 +        or	%g3, 0x1, %g3 +        sta	%g3, [%g2] ASI_M_BYPASS +        add	%g2, 4, %g2			! s+0x9e8 +        add	%g2, 0x1000 - 0x9e8, %g3	! 7th l3 table for rom at s+0x1000 +        srl	%g3, 0x4, %g3 +        or	%g3, 0x1, %g3 +        sta	%g3, [%g2] ASI_M_BYPASS +        add	%g2, 4, %g2			! s+0x9ec +        add	%g2, 0x1100 - 0x9ec, %g3	! 8th l3 table for rom at s+0x1100 +        srl	%g3, 0x4, %g3 +        or	%g3, 0x1, %g3 +        sta	%g3, [%g2] ASI_M_BYPASS +      add	%g2, 0xa00-0x9ec, %g2		! s+0xa00 + +        /* Use end of ram for code, rodata, data, and bss +	sections. SunOS wants to write to trap table... */ +        set	_end, %g6 +        set	_start, %g4 +        sub     %g6, %g4, %g6 +        sub     %g1, %g6, %g3 +        set	0x1000, %g5 +        sub     %g3, %g5, %g3 +        sub     %g3, %g5, %g3                   ! start of ROM copy +        mov     %g3, %g7                        ! save in %g7 +        srl     %g6, 12, %g6                    ! # of all pages +1:      srl	%g3, 0x4, %g4 +        or	%g4, ((7 << 2) | 2), %g4        ! 7 = U: --- S: RWX +        sta	%g4, [%g2] ASI_M_BYPASS +        add	%g2, 4, %g2 +        add	%g3, %g5, %g3 +        deccc	%g6 +        bne	1b +         nop + +        mov	%g1, %g6                        ! %g6 = memory size + +        /* Copy the code, rodata and data sections from ROM. */ +        sub     %g7, 4, %g3 +        set	_start - 4, %g4                 ! First address of TEXT - 4 +        set	_bss, %g5                       ! Last address of DATA +        ba	2f +         nop +1: +        lda     [%g4] ASI_M_KERNELTXT, %g1 +        sta	%g1, [%g3] ASI_M_BYPASS +2: +        cmp     %g4, %g5 +        add     %g3, 0x4, %g3 +        bl      1b +         add    %g4, 0x4, %g4 + +        set     0x2000, %g3 +        sub     %g6, %g3, %g7                   ! ctx table at s+0x0 +        set     AC_M_CTPR, %g2 +        srl     %g7, 4, %g7 +        sta     %g7, [%g2] ASI_M_MMUREGS	! set ctx table ptr +        set     AC_M_CXR, %g2 +        sta     %g0, [%g2] ASI_M_MMUREGS	! context 0 +        set     highmem, %g2 +        set	1, %g1 +        jmp     %g2 +         sta    %g1, [%g0] ASI_M_MMUREGS	! enable mmu +highmem: +        /* +         * The code which enables traps is a simplified version of +         * kernel head.S. +         * +         * We know number of windows as 8 so we do not calculate them. +         * The deadwood is here for any case. +         */ + +        /* Turn on Supervisor, EnableFloating, and all the PIL bits. +         * Also puts us in register window zero with traps off. +         */ +        set	(PSR_PS | PSR_S | PSR_PIL | PSR_EF), %g2 +        wr	%g2, 0x0, %psr +        WRITE_PAUSE + +        /* Zero out our BSS section. */ +        set	_bss - 4, %o0           ! First address of BSS +        set	_estack - 4, %o1        ! Last address of BSS +        ba	2f +         nop +1: +        st	%g0, [%o0] +2: +        subcc	%o0, %o1, %g0 +        bl	1b +         add	%o0, 0x4, %o0 + +        set     trap_table, %g1 +        wr      %g1, 0x0, %tbr + +        set     qemu_mem_size, %g1 +        st      %g6, [%g1] + +        set     _end, %o0                       ! Store va->pa conversion factor +        set     _start, %o2 +        sub     %o0, %o2, %o0 +        sub     %g6, %o0, %o0 +        set     0x2000, %o1 +        sub     %o0, %o1, %o0                   ! start of ROM copy +        sub     %o2, %o0, %o0                   ! start of ROM copy +        set     va_shift, %g1 +        st      %o0, [%g1] + +        set     qemu_machine_type, %g1 +        mov     %y, %g2 +        st      %g2, [%g1] + +        /* Compute NWINDOWS and stash it away. Now uses %wim trick explained +         * in the V8 manual. Ok, this method seems to work, Sparc is cool... +         * No, it doesn't work, have to play the save/readCWP/restore trick. +         */ + +        wr      %g0, 0x0, %wim                  ! so we do not get a trap +        WRITE_PAUSE + +        save + +        rd      %psr, %g3 + +        restore + +        and     %g3, 0x1f, %g3 +        add     %g3, 0x1, %g3 + +        mov     2, %g1 +        wr      %g1, 0x0, %wim                  ! make window 1 invalid +        WRITE_PAUSE + +        cmp     %g3, 0x7 +        bne     1f +         nop + +        /* Adjust our window handling routines to +         * do things correctly on 7 window Sparcs. +         */ +#define PATCH_INSN(src, dest) \ +        set     src, %g5; \ +        set     dest, %g2; \ +        ld      [%g5], %g4; \ +        st      %g4, [%g2]; + +        /* Patch for window spills... */ +        PATCH_INSN(spnwin_patch1_7win, spnwin_patch1) +        PATCH_INSN(spnwin_patch2_7win, spnwin_patch2) + +        /* Patch for window fills... */ +        PATCH_INSN(fnwin_patch1_7win, fnwin_patch1) +        PATCH_INSN(fnwin_patch2_7win, fnwin_patch2) + +1: +        /* Finally, turn on traps so that we can call c-code. */ +        rd	%psr, %g3 +        wr	%g3, 0x0, %psr +        WRITE_PAUSE + +        wr	%g3, PSR_ET, %psr +        WRITE_PAUSE + +        set     0, %fp +        call    __switch_context_nosave +         nop + +        /* We get here when the main context switches back to +         * the boot context. +         * Return to previous bootloader. +         */ +        ret +         nop + +ss2_ss1000_halt: +        set     SER_ADDR2, %o0 +        set     SER_ADDR1000, %o1 +        mov     0x05, %o3 /* Reg 5, TXCTRL2 */ +        stba    %o3, [%o0] ASI_M_BYPASS +        stba    %o3, [%o1] ASI_M_CTL +        mov     0x68, %o3 /* 8 bits, Tx enabled */ +        stba    %o3, [%o0] ASI_M_BYPASS +        stba    %o3, [%o1] ASI_M_CTL +        add     %o0, 2, %o0 +        add     %o1, 2, %o1 + +1:      lduba   [%o2] ASI_M_KERNELTXT, %o3 +        cmp     %o3, 0 +        be      2f +         nop +        stba    %o3, [%o0] ASI_M_BYPASS +        stba    %o3, [%o1] ASI_M_CTL +        b       1b +         inc    %o2 +bad_conf: +2:      b       2b +         nop + +        .section .rodata +ss2_error: +        .string "Sun4c machines are not supported by OpenBIOS yet, freezing\r\n" +ss1000_error: +        .string "Sun4d machines are not supported by OpenBIOS yet, freezing\r\n" diff --git a/roms/openbios/arch/sparc32/init.fs b/roms/openbios/arch/sparc32/init.fs new file mode 100644 index 00000000..814c720c --- /dev/null +++ b/roms/openbios/arch/sparc32/init.fs @@ -0,0 +1,83 @@ +:noname +  ."   Type 'help' for detailed information" cr +  \ ."   boot secondary slave cdrom: " cr +  \ ."    0 >  boot hd:2,\boot\vmlinuz root=/dev/hda2" cr +  ; DIAG-initializer + +: make-openable ( path ) +  find-dev if +    begin ?dup while +      \ install trivial open and close methods +      dup active-package! is-open +      parent +    repeat +  then +; + +: preopen ( chosen-str node-path ) +  2dup make-openable + +  " /chosen" find-device +  open-dev ?dup if +    encode-int 2swap property +  else +    2drop +  then +; + +:noname +  set-defaults +; PREPOST-initializer + +\ preopen device nodes (and store the ihandles under /chosen) +:noname +  " memory" " /memory" preopen +  " mmu" " /virtual-memory" preopen +; SYSTEM-initializer + +device-end + +: rmap@    ( virt -- rmentry ) +  drop 0 +  ; + +\ D5.3 SBus specific on-board memory address space +: obmem ( -- space ) +  0 +  ; + +\ (peek) and (poke) implementation +defer sfsr@ +defer ignore-dfault + +:noname +  \ ( addr xt -- false | value true ) +  sfsr@ drop            \ Clear any existing MMU fault status + +  -1 ignore-dfault !    \ Disable data fault trap +  execute +  0 ignore-dfault !     \ Enable data fault trap + +  sfsr@ 0= if +    true +  else +    drop false          \ Failed, drop the read value +  then +; to (peek) + +:noname +  \ ( value addr xt -- okay? ) +  sfsr@ drop            \ Clear any existing MMU fault status + +  -1 ignore-dfault !    \ Disable data fault trap +  execute +  0 ignore-dfault !     \ Enable data fault trap + +  sfsr@ 0=              \ true if no fault +; to (poke) + +\ Load TCX FCode driver blob +[IFDEF] CONFIG_DRIVER_SBUS +  -1 value tcx-driver-fcode +  " QEMU,tcx.bin" $encode-file to tcx-driver-fcode +[THEN] diff --git a/roms/openbios/arch/sparc32/ldscript b/roms/openbios/arch/sparc32/ldscript new file mode 100644 index 00000000..b543c159 --- /dev/null +++ b/roms/openbios/arch/sparc32/ldscript @@ -0,0 +1,73 @@ +OUTPUT_FORMAT(elf32-sparc) +OUTPUT_ARCH(sparc) + +/* QEMU ELF loader can't handle very complex files, so we put ELFBoot +info to rodata and put initctx to data.*/ + +ENTRY(trap_table) + +/* Initial load address + */ +BASE_ADDR = 0xffd00000; + +/* 16KB stack */ +STACK_SIZE = 16384; +VMEM_SIZE = 128 * 1024; +IOMEM_SIZE = 256 * 1024 + 768 * 1024; + +SECTIONS +{ +    . = BASE_ADDR; + +    /* Start of the program. +     * Now the version string is in the note, we must include it +     * in the program. Otherwise we lose the string after relocation. */ +    _start = .; + +    /* Normal sections */ +    .text ALIGN(4096): { +        *(.text.vectors) +        *(.text) +        *(.text.*) +    } +    .rodata ALIGN(4096): { +        _rodata = .; +	sound_drivers_start = .; +	*(.rodata.sound_drivers) +	sound_drivers_end = .; +	*(.rodata) +	*(.rodata.*) +        *(.note.ELFBoot) +    } +    .data ALIGN(4096): { +        _data = .; +        *(.data) +        *(.data.*) +    } + +    .bss ALIGN(4096): { +        _bss = .; +	*(.bss) +	*(.bss.*) +	*(COMMON) + +	. = ALIGN(4096); +	_vmem = .; +	. += VMEM_SIZE; +        _evmem = .; + +	_stack = .; +	. += STACK_SIZE; +	. = ALIGN(16); +	_estack = .; +    } + +    . = ALIGN(4096); +    _end = .; +    _iomem = _end + IOMEM_SIZE; + +    /* We discard .note sections other than .note.ELFBoot, +     * because some versions of GCC generates useless ones. */ + +    /DISCARD/ : { *(.comment*) *(.note.*) } +} diff --git a/roms/openbios/arch/sparc32/lib.c b/roms/openbios/arch/sparc32/lib.c new file mode 100644 index 00000000..d27b604c --- /dev/null +++ b/roms/openbios/arch/sparc32/lib.c @@ -0,0 +1,397 @@ +/* lib.c + * tag: simple function library + * + * Copyright (C) 2003 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#include "libc/vsprintf.h" +#include "libopenbios/bindings.h" +#include "arch/sparc32/ofmem_sparc32.h" +#include "asm/asi.h" +#include "pgtsrmmu.h" +#include "openprom.h" +#include "libopenbios/sys_info.h" +#include "boot.h" +#include "romvec.h" + +#define NCTX_SWIFT  0x100 +#define LOWMEMSZ 32 * 1024 * 1024 + +#ifdef CONFIG_DEBUG_MEM +#define DPRINTF(fmt, args...)                   \ +    do { printk(fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) +#endif + +/* Format a string and print it on the screen, just like the libc + * function printf. + */ +int printk( const char *fmt, ... ) +{ +        char *p, buf[512]; +	va_list args; +	int i; + +	va_start(args, fmt); +        i = vsnprintf(buf, sizeof(buf), fmt, args); +	va_end(args); + +	for( p=buf; *p; p++ ) +		putchar(*p); +	return i; +} + +/* + * Allocatable memory chunk. + */ +struct mem { +    char *start, *uplim; +    char *curp; +}; + +struct mem cdvmem;              /* Current device virtual memory space */ + +unsigned int va_shift; +unsigned long *l1; +static unsigned long *context_table; + +struct linux_mlist_v0 *ptphys; +struct linux_mlist_v0 *ptmap; +struct linux_mlist_v0 *ptavail; + +/* Private functions for mapping between physical/virtual addresses */  +phys_addr_t +va2pa(unsigned long va) +{ +    if ((va >= (unsigned long)&_start) && +        (va < (unsigned long)&_end)) +        return va - va_shift; +    else +        return va; +} + +unsigned long +pa2va(phys_addr_t pa) +{ +    if ((pa + va_shift >= (unsigned long)&_start) && +        (pa + va_shift < (unsigned long)&_end)) +        return pa + va_shift; +    else +        return pa; +} + +void * +malloc(int size) +{ +    return ofmem_malloc(size); +} + +void * +realloc( void *ptr, size_t size ) +{ +    return ofmem_realloc(ptr, size); +} + +void +free(void *ptr) +{ +    ofmem_free(ptr); +} + +/* + * Allocate memory. This is reusable. + */ +void +mem_init(struct mem *t, char *begin, char *limit) +{ +    t->start = begin; +    t->uplim = limit; +    t->curp = begin; +} + +void * +mem_alloc(struct mem *t, int size, int align) +{ +    char *p; +    unsigned long pa; + +    // The alignment restrictions refer to physical, not virtual +    // addresses +    pa = va2pa((unsigned long)t->curp) + (align - 1); +    pa &= ~(align - 1); +    p = (char *)pa2va(pa); + +    if ((unsigned long)p >= (unsigned long)t->uplim || +        (unsigned long)p + size > (unsigned long)t->uplim) +        return NULL; +    t->curp = p + size; + +    return p; +} + +/* + * D5.3 pgmap@ ( va -- pte ) + */ +static void +pgmap_fetch(void) +{ +    uint32_t pte; +    unsigned long va, pa; + +    va = POP(); + +    pa = find_pte(va, 0); +    if (pa == 1 || pa == 2) +        goto error; +    pte = *(uint32_t *)pa; +    DPRINTF("pgmap@: va 0x%lx pa 0x%lx pte 0x%x\n", va, pa, pte); + +    PUSH(pte); +    return; + error: +    PUSH(0); +} + +/* + * D5.3 pgmap! ( pte va -- ) + */ +static void +pgmap_store(void) +{ +    uint32_t pte; +    unsigned long va, pa; + +    va = POP(); +    pte = POP(); + +    pa = find_pte(va, 1); +    *(uint32_t *)pa = pte; +    DPRINTF("pgmap!: va 0x%lx pa 0x%lx pte 0x%x\n", va, pa, pte); +} + +/* + * D5.3 map-pages ( pa space va size -- ) + */ +static void +ob_map_pages(void) +{ +    unsigned long va; +    int size; +    uint64_t pa; + +    size = POP(); +    va = POP(); +    pa = POP(); +    pa <<= 32; +    pa |= POP() & 0xffffffff; + +    ofmem_arch_map_pages(pa, va, size, ofmem_arch_default_translation_mode(pa)); +} + +char *obp_dumb_mmap(char *va, int which_io, unsigned int pa, +                    unsigned int size) +{ +    uint64_t mpa = ((uint64_t)which_io << 32) | (uint64_t)pa; + +    ofmem_arch_map_pages(mpa, (unsigned long)va, size, ofmem_arch_default_translation_mode(mpa)); +    return va; +} + +void obp_dumb_munmap(__attribute__((unused)) char *va, +                     __attribute__((unused)) unsigned int size) +{ +    DPRINTF("obp_dumb_munmap: virta 0x%x, sz %d\n", (unsigned int)va, size); +} + +char *obp_memalloc(char *va, unsigned int size, unsigned int align) +{ +    phys_addr_t phys; +    ucell virt; + +    DPRINTF("obp_memalloc: virta 0x%x, sz %d, align %d\n", (unsigned int)va, size, align);     +     +    /* Claim physical memory */ +    phys = ofmem_claim_phys(-1, size, align); + +    /* Claim virtual memory */ +    virt = ofmem_claim_virt(pointer2cell(va), size, 0); + +    /* Map the memory */ +    ofmem_map(phys, virt, size, ofmem_arch_default_translation_mode(phys)); + +    return cell2pointer(virt); +} + +char *obp_dumb_memalloc(char *va, unsigned int size) +{ +    unsigned long align = size; +    phys_addr_t phys; +    ucell virt; +     +    DPRINTF("obp_dumb_memalloc: virta 0x%x, sz %d\n", (unsigned int)va, size);     +     +    /* Solaris seems to assume that the returned value is physically aligned to size. +       e.g. it is used for setting up page tables. */ +     +    /* Claim physical memory */ +    phys = ofmem_claim_phys(-1, size, align); + +    /* Claim virtual memory - if va == NULL then we choose va address */ +    if (va == NULL) { +        virt = ofmem_claim_virt((ucell)-1, size, align);         +    } else { +        virt = ofmem_claim_virt(pointer2cell(va), size, 0); +    } + +    /* Map the memory */ +    ofmem_map(phys, virt, size, ofmem_arch_default_translation_mode(phys)); + +    return cell2pointer(virt); +} + +void obp_dumb_memfree(char *va, unsigned size) +{ +    phys_addr_t phys; +    ucell cellmode; + +    DPRINTF("obp_dumb_memfree: virta 0x%x, sz %d\n", (unsigned int)va, size); + +    phys = ofmem_translate(pointer2cell(va), &cellmode); + +    ofmem_unmap(pointer2cell(va), size); +    ofmem_release_virt(pointer2cell(va), size); +    ofmem_release_phys(phys, size); +} + +/* Data fault handling routines */ + +extern unsigned int ignore_dfault; + +/* ( -- reg ) */ +static void srmmu_get_sfsr(void) +{ +    PUSH(srmmu_get_fstatus()); +} + +/* ( -- addr ) */ +static void ignore_dfault_addr(void) +{ +    PUSH(pointer2cell(&ignore_dfault)); +} + +void +ob_init_mmu(void) +{ +    ucell *memreg; +    ucell *virtreg; +    phys_addr_t virtregsize; +    ofmem_t *ofmem = ofmem_arch_get_private(); + +    /* Find the phandles for the /memory and /virtual-memory nodes */ +    push_str("/memory"); +    fword("find-package"); +    POP(); +    s_phandle_memory = POP(); + +    push_str("/virtual-memory"); +    fword("find-package"); +    POP(); +    s_phandle_mmu = POP(); + +    ofmem_register(s_phandle_memory, s_phandle_mmu); + +    /* Setup /memory:reg (totphys) property */ +    memreg = malloc(3 * sizeof(ucell)); +    ofmem_arch_encode_physaddr(memreg, 0); /* physical base */ +    memreg[2] = (ucell)ofmem->ramsize; /* size */ + +    push_str("/memory"); +    fword("find-device"); +    PUSH(pointer2cell(memreg)); +    PUSH(3 * sizeof(ucell)); +    push_str("reg"); +    PUSH_ph(s_phandle_memory); +    fword("encode-property"); + +    /* Setup /virtual-memory:reg property */ +    virtregsize = ((phys_addr_t)((ucell)-1) + 1) / 2; +     +    virtreg = malloc(6 * sizeof(ucell)); +    ofmem_arch_encode_physaddr(virtreg, 0); +    virtreg[2] = virtregsize; +    ofmem_arch_encode_physaddr(&virtreg[3], virtregsize); +    virtreg[5] = virtregsize; +     +    push_str("/virtual-memory"); +    fword("find-device"); +    PUSH(pointer2cell(virtreg)); +    PUSH(6 * sizeof(ucell)); +    push_str("reg"); +    PUSH_ph(s_phandle_mmu); +    fword("encode-property"); +     +    PUSH(0); +    fword("active-package!"); +    bind_func("pgmap@", pgmap_fetch); +    bind_func("pgmap!", pgmap_store); +    bind_func("map-pages", ob_map_pages); + +    /* Install data fault handler words for cpeek etc. */ +    PUSH_xt(bind_noname_func(srmmu_get_sfsr)); +    feval("to sfsr@"); +    PUSH_xt(bind_noname_func(ignore_dfault_addr)); +    feval("to ignore-dfault"); +} + +/* + * Switch page tables. + */ +void +init_mmu_swift(void) +{ +    unsigned int addr, i; +    unsigned long pa, va; +    int size; + +    ofmem_posix_memalign((void *)&context_table, NCTX_SWIFT * sizeof(int), +                   NCTX_SWIFT * sizeof(int)); +    ofmem_posix_memalign((void *)&l1, 256 * sizeof(int), 256 * sizeof(int)); + +    context_table[0] = (((unsigned long)va2pa((unsigned long)l1)) >> 4) | +        SRMMU_ET_PTD; + +    for (i = 1; i < NCTX_SWIFT; i++) { +        context_table[i] = SRMMU_ET_INVALID; +    } +    for (i = 0; i < 256; i++) { +        l1[i] = SRMMU_ET_INVALID; +    } + +    // text, rodata, data, and bss mapped to end of RAM +    va = (unsigned long)&_start; +    size = (unsigned long)&_end - (unsigned long)&_start; +    pa = va2pa(va); +    ofmem_arch_map_pages(pa, va, size, ofmem_arch_default_translation_mode(pa)); +    ofmem_map_page_range(pa, va, size, ofmem_arch_default_translation_mode(pa)); + +    // 1:1 mapping for RAM (don't map page 0 to allow catching of NULL dereferences)                                                                                                                                             +    ofmem_arch_map_pages(PAGE_SIZE, PAGE_SIZE, LOWMEMSZ - PAGE_SIZE, ofmem_arch_default_translation_mode(0));                                                                                                                    +    ofmem_map_page_range(PAGE_SIZE, PAGE_SIZE, LOWMEMSZ - PAGE_SIZE, ofmem_arch_default_translation_mode(0)); + +    /* +     * Flush cache +     */ +    for (addr = 0; addr < 0x2000; addr += 0x10) { +        __asm__ __volatile__ ("sta %%g0, [%0] %1\n\t" : : +                              "r" (addr), "i" (ASI_M_DATAC_TAG)); +        __asm__ __volatile__ ("sta %%g0, [%0] %1\n\t" : : +                              "r" (addr<<1), "i" (ASI_M_TXTC_TAG)); +    } +    srmmu_set_context(0); +    srmmu_set_ctable_ptr(va2pa((unsigned long)context_table)); +    srmmu_flush_whole_tlb(); +} diff --git a/roms/openbios/arch/sparc32/linux_load.c b/roms/openbios/arch/sparc32/linux_load.c new file mode 100644 index 00000000..26f7fc6b --- /dev/null +++ b/roms/openbios/arch/sparc32/linux_load.c @@ -0,0 +1,648 @@ +/* + * Linux/i386 loader + * Supports bzImage, zImage and Image format. + * + * Based on work by Steve Gehlbach. + * Portions are taken from mkelfImage. + * + * 2003-09 by SONE Takeshi + */ + +#include "config.h" +#include "kernel/kernel.h" +#include "libopenbios/bindings.h" +#include "libopenbios/sys_info.h" +#include "context.h" +#include "libc/diskio.h" +#include "boot.h" + +#define printf printk +#define debug printk +#define strtoull_with_suffix strtol + +#define LINUX_PARAM_LOC 0x90000 +#define COMMAND_LINE_LOC 0x91000 +#define GDT_LOC 0x92000 +#define STACK_LOC 0x93000 + +#define E820MAX	32		/* number of entries in E820MAP */ +struct e820entry { +	unsigned long long addr;	/* start of memory segment */ +	unsigned long long size;	/* size of memory segment */ +	unsigned long type;		/* type of memory segment */ +#define E820_RAM	1 +#define E820_RESERVED	2 +#define E820_ACPI	3 /* usable as RAM once ACPI tables have been read */ +#define E820_NVS	4 +}; + +/* The header of Linux/i386 kernel */ +struct linux_header { +    uint8_t  reserved1[0x1f1];		/* 0x000 */ +    uint8_t  setup_sects;		/* 0x1f1 */ +    uint16_t root_flags;		/* 0x1f2 */ +    uint8_t  reserved2[6];		/* 0x1f4 */ +    uint16_t vid_mode;			/* 0x1fa */ +    uint16_t root_dev;			/* 0x1fc */ +    uint16_t boot_sector_magic;		/* 0x1fe */ +    /* 2.00+ */ +    uint8_t  reserved3[2];		/* 0x200 */ +    uint8_t  header_magic[4];		/* 0x202 */ +    uint16_t protocol_version;		/* 0x206 */ +    uint32_t realmode_swtch;		/* 0x208 */ +    uint16_t start_sys;			/* 0x20c */ +    uint16_t kver_addr;			/* 0x20e */ +    uint8_t  type_of_loader;		/* 0x210 */ +    uint8_t  loadflags;			/* 0x211 */ +    uint16_t setup_move_size;		/* 0x212 */ +    uint32_t code32_start;		/* 0x214 */ +    uint32_t ramdisk_image;		/* 0x218 */ +    uint32_t ramdisk_size;		/* 0x21c */ +    uint8_t  reserved4[4];		/* 0x220 */ +    /* 2.01+ */ +    uint16_t heap_end_ptr;		/* 0x224 */ +    uint8_t  reserved5[2];		/* 0x226 */ +    /* 2.02+ */ +    uint32_t cmd_line_ptr;		/* 0x228 */ +    /* 2.03+ */ +    uint32_t initrd_addr_max;		/* 0x22c */ +} __attribute__ ((packed)); + + +/* Paramters passed to 32-bit part of Linux + * This is another view of the structure above.. */ +struct linux_params { +    uint8_t  orig_x;			/* 0x00 */ +    uint8_t  orig_y;			/* 0x01 */ +    uint16_t ext_mem_k;			/* 0x02 -- EXT_MEM_K sits here */ +    uint16_t orig_video_page;		/* 0x04 */ +    uint8_t  orig_video_mode;		/* 0x06 */ +    uint8_t  orig_video_cols;		/* 0x07 */ +    uint16_t unused2;			/* 0x08 */ +    uint16_t orig_video_ega_bx;		/* 0x0a */ +    uint16_t unused3;			/* 0x0c */ +    uint8_t  orig_video_lines;		/* 0x0e */ +    uint8_t  orig_video_isVGA;		/* 0x0f */ +    uint16_t orig_video_points;		/* 0x10 */ + +    /* VESA graphic mode -- linear frame buffer */ +    uint16_t lfb_width;			/* 0x12 */ +    uint16_t lfb_height;		/* 0x14 */ +    uint16_t lfb_depth;			/* 0x16 */ +    uint32_t lfb_base;			/* 0x18 */ +    uint32_t lfb_size;			/* 0x1c */ +    uint16_t cl_magic;			/* 0x20 */ +#define CL_MAGIC_VALUE 0xA33F +    uint16_t cl_offset;			/* 0x22 */ +    uint16_t lfb_linelength;		/* 0x24 */ +    uint8_t  red_size;			/* 0x26 */ +    uint8_t  red_pos;			/* 0x27 */ +    uint8_t  green_size;		/* 0x28 */ +    uint8_t  green_pos;			/* 0x29 */ +    uint8_t  blue_size;			/* 0x2a */ +    uint8_t  blue_pos;			/* 0x2b */ +    uint8_t  rsvd_size;			/* 0x2c */ +    uint8_t  rsvd_pos;			/* 0x2d */ +    uint16_t vesapm_seg;		/* 0x2e */ +    uint16_t vesapm_off;		/* 0x30 */ +    uint16_t pages;			/* 0x32 */ +    uint8_t  reserved4[12];		/* 0x34 -- 0x3f reserved for future expansion */ + +    //struct apm_bios_info apm_bios_info;	/* 0x40 */ +    uint8_t  apm_bios_info[0x40]; +    //struct drive_info_struct drive_info;	/* 0x80 */ +    uint8_t  drive_info[0x20]; +    //struct sys_desc_table sys_desc_table;	/* 0xa0 */ +    uint8_t  sys_desc_table[0x140]; +    uint32_t alt_mem_k;			/* 0x1e0 */ +    uint8_t  reserved5[4];		/* 0x1e4 */ +    uint8_t  e820_map_nr;		/* 0x1e8 */ +    uint8_t  reserved6[9];		/* 0x1e9 */ +    uint16_t mount_root_rdonly;		/* 0x1f2 */ +    uint8_t  reserved7[4];		/* 0x1f4 */ +    uint16_t ramdisk_flags;		/* 0x1f8 */ +#define RAMDISK_IMAGE_START_MASK  	0x07FF +#define RAMDISK_PROMPT_FLAG		0x8000 +#define RAMDISK_LOAD_FLAG		0x4000 +    uint8_t  reserved8[2];		/* 0x1fa */ +    uint16_t orig_root_dev;		/* 0x1fc */ +    uint8_t  reserved9[1];		/* 0x1fe */ +    uint8_t  aux_device_info;		/* 0x1ff */ +    uint8_t  reserved10[2];		/* 0x200 */ +    uint8_t  param_block_signature[4];	/* 0x202 */ +    uint16_t param_block_version;	/* 0x206 */ +    uint8_t  reserved11[8];		/* 0x208 */ +    uint8_t  loader_type;		/* 0x210 */ +#define LOADER_TYPE_LOADLIN         1 +#define LOADER_TYPE_BOOTSECT_LOADER 2 +#define LOADER_TYPE_SYSLINUX        3 +#define LOADER_TYPE_ETHERBOOT       4 +#define LOADER_TYPE_KERNEL          5 +    uint8_t  loader_flags;		/* 0x211 */ +    uint8_t  reserved12[2];		/* 0x212 */ +    uint32_t kernel_start;		/* 0x214 */ +    uint32_t initrd_start;		/* 0x218 */ +    uint32_t initrd_size;		/* 0x21c */ +    uint8_t  reserved12_5[8];		/* 0x220 */ +    uint32_t cmd_line_ptr;		/* 0x228 */ +    uint8_t  reserved13[164];		/* 0x22c */ +    struct e820entry e820_map[E820MAX];	/* 0x2d0 */ +    uint8_t  reserved16[688];		/* 0x550 */ +#define COMMAND_LINE_SIZE 256 +    /* Command line is copied here by 32-bit i386/kernel/head.S. +     * So I will follow the boot protocol, rather than putting it +     * directly here. --ts1 */ +    uint8_t  command_line[COMMAND_LINE_SIZE]; /* 0x800 */ +    uint8_t  reserved17[1792];		/* 0x900 - 0x1000 */ +}; + +static uint64_t forced_memsize; +static int fd; + +static unsigned long file_size(void) +{ +	long long fpos, fsize; + +	/* Save current position */ +	fpos = tell(fd); + +	/* Go to end of file and get position */ +	seek_io(fd, -1); +	fsize = tell(fd); + +	/* Go back to old position */ +	seek_io(fd, 0); +	seek_io(fd, fpos); + +	return fsize; +} + +/* Load the first part the file and check if it's Linux */ +static uint32_t load_linux_header(struct linux_header *hdr) +{ +    int load_high; +    uint32_t kern_addr; + +    if (read_io(fd, hdr, sizeof *hdr) != sizeof *hdr) { +	debug("Can't read Linux header\n"); +	return 0; +    } +    if (hdr->boot_sector_magic != 0xaa55) { +	debug("Not a Linux kernel image\n"); +	return 0; +    } + +    /* Linux is found. Print some information */ +    if (memcmp(hdr->header_magic, "HdrS", 4) != 0) { +	/* This may be floppy disk image or something. +	 * Perform a simple (incomplete) sanity check. */ +	if (hdr->setup_sects >= 16 +		|| file_size() - (hdr->setup_sects<<9) >= 512<<10) { +	    debug("This looks like a bootdisk image but not like Linux...\n"); +	    return 0; +	} + +	printf("Possible very old Linux"); +	/* This kernel does not even have a protocol version. +	 * Force the value. */ +	hdr->protocol_version = 0; /* pre-2.00 */ +    } else +	printf("Found Linux"); +    if (hdr->protocol_version >= 0x200 && hdr->kver_addr) { +	char kver[256]; +	seek_io(fd, hdr->kver_addr + 0x200); +	if (read_io(fd, kver, sizeof kver) != 0) { +	    kver[255] = 0; +	    printf(" version %s", kver); +	} +    } +    debug(" (protocol %#x)", hdr->protocol_version); +    load_high = 0; +    if (hdr->protocol_version >= 0x200) { +	debug(" (loadflags %#x)", hdr->loadflags); +	load_high = hdr->loadflags & 1; +    } +    if (load_high) { +	printf(" bzImage"); +	kern_addr = 0x100000; +    } else { +	printf(" zImage or Image"); +	kern_addr = 0x1000; +    } +    printf(".\n"); + +    return kern_addr; +} + +/* Set up parameters for 32-bit kernel */ +static void +init_linux_params(struct linux_params *params, struct linux_header *hdr) +{ +    debug("Setting up paramters at %#lx\n", virt_to_phys(params)); +    memset(params, 0, sizeof *params); + +    /* Copy some useful values from header */ +    params->mount_root_rdonly = hdr->root_flags; +    params->orig_root_dev = hdr->root_dev; + +    /* Video parameters. +     * This assumes we have VGA in standard 80x25 text mode, +     * just like our vga.c does. +     * Cursor position is filled later to allow some more printf's. */ +    params->orig_video_mode = 3; +    params->orig_video_cols = 80; +    params->orig_video_lines = 25; +    params->orig_video_isVGA = 1; +    params->orig_video_points = 16; + +    params->loader_type = 0xff; /* Unregistered Linux loader */ +} + +/* Memory map */ +static void +set_memory_size(struct linux_params *params, struct sys_info *info) +{ +    int i; +    uint64_t end; +    uint32_t ramtop = 0; +    struct e820entry *linux_map; +    struct memrange *filo_map; + +    linux_map = params->e820_map; +    filo_map = info->memrange; +    for (i = 0; i < info->n_memranges; i++, linux_map++, filo_map++) { +	if (i < E820MAX) { +	    /* Convert to BIOS e820 style */ +	    linux_map->addr = filo_map->base; +	    linux_map->size = filo_map->size; +	    linux_map->type = E820_RAM; +	    debug("%016Lx - %016Lx\n", linux_map->addr, +		    linux_map->addr + linux_map->size); +	    params->e820_map_nr = i+1; +	} + +	/* Find out top of RAM. XXX This ignores hole above 1MB */ +	end = filo_map->base + filo_map->size; +	if (end < (1ULL << 32)) { /* don't count memory above 4GB */ +	    if (end > ramtop) +		ramtop = (uint32_t) end; +	} +    } +    debug("ramtop=%#x\n", ramtop); +    /* Size of memory above 1MB in KB */ +    params->alt_mem_k = (ramtop - (1<<20)) >> 10; +    /* old style, 64MB max */ +    if (ramtop >= (64<<20)) +	params->ext_mem_k = (63<<10); +    else +	params->ext_mem_k = params->alt_mem_k; +    debug("ext_mem_k=%d, alt_mem_k=%d\n", params->ext_mem_k, params->alt_mem_k); +} + +/* + * Parse command line + * Some parameters, like initrd=<file>, are not passed to kernel, + * we are responsible to process them. + * Parameters for kernel are copied to kern_cmdline. Returns name of initrd. + */ +static char *parse_command_line(const char *orig_cmdline, char *kern_cmdline) +{ +    const char *start, *sep, *end, *val; +    char name[64]; +    unsigned long len; +    int k_len; +    int to_kern; +    char *initrd = NULL; +    int toolong = 0; + +    forced_memsize = 0; + +    if (!orig_cmdline) { +        *kern_cmdline = '\0'; +        return NULL; +    } + +    k_len = 0; +    debug("original command line: \"%s\"\n", orig_cmdline); +    debug("kernel command line at %#lx\n", virt_to_phys(kern_cmdline)); + +    start = orig_cmdline; +    while (*start == ' ') +	start++; +    while (*start) { +	end = strchr(start, ' '); +	if (!end) +	    end = start + strlen(start); +	sep = strchr(start, '='); +	if (!sep || sep > end) +	    sep = end; +	len = sep - start; +	if (len >= sizeof(name)) +	    len = sizeof(name) - 1; +	memcpy(name, start, len); +	name[len] = 0; + +	if (*sep == '=') { +	    val = sep + 1; +	    len = end - val; +	} else { +            val = NULL; +	    len = 0; +	} + +	/* Only initrd= and mem= are handled here. vga= is not, +	 * which I believe is a paramter to the realmode part of Linux, +	 * which we don't execute. */ +	if (strcmp(name, "initrd") == 0) { +	    if (!val) +		printf("Missing filename to initrd parameter\n"); +	    else { +		initrd = malloc(len + 1); +		memcpy(initrd, val, len); +		initrd[len] = 0; +		debug("initrd=%s\n", initrd); +	    } +	    /* Don't pass this to kernel */ +	    to_kern = 0; +	} else if (strcmp(name, "mem") == 0) { +	    if (!val) +		printf("Missing value for mem parameter\n"); +	    else { +		forced_memsize = strtoull_with_suffix(val, (char**)&val, 0); +		if (forced_memsize == 0) +		    printf("Invalid mem option, ignored\n"); +		if (val != end) { +		    printf("Garbage after mem=<size>, ignored\n"); +		    forced_memsize = 0; +		} +		debug("mem=%Lu\n", forced_memsize); +	    } +	    /* mem= is for both loader and kernel */ +	    to_kern = 1; +	} else +	    to_kern = 1; + +	if (to_kern) { +	    /* Copy to kernel command line buffer */ +	    if (k_len != 0) +		kern_cmdline[k_len++] = ' '; /* put separator */ +	    len = end - start; +	    if (k_len + len >= COMMAND_LINE_SIZE) { +		len = COMMAND_LINE_SIZE - k_len - 1; +		if (!toolong) { +		    printf("Kernel command line is too long; truncated to " +			    "%d bytes\n", COMMAND_LINE_SIZE-1); +		    toolong = 1; +		} +	    } +	    memcpy(kern_cmdline + k_len, start, len); +	    k_len += len; +	} + +	start = end; +	while (*start == ' ') +	    start++; +    } +    kern_cmdline[k_len] = 0; +    debug("kernel command line (%d bytes): \"%s\"\n", k_len, kern_cmdline); + +    return initrd; +} + +/* Set command line location */ +static void set_command_line_loc(struct linux_params *params, +	struct linux_header *hdr) +{ +    if (hdr->protocol_version >= 0x202) { +	/* new style */ +	params->cmd_line_ptr = COMMAND_LINE_LOC; +    } else { +	/* old style */ +	params->cl_magic = CL_MAGIC_VALUE; +	params->cl_offset = COMMAND_LINE_LOC - LINUX_PARAM_LOC; +    } +} + +/* Load 32-bit part of kernel */ +static int load_linux_kernel(struct linux_header *hdr, uint32_t kern_addr) +{ +    uint32_t kern_offset, kern_size; + +    if (hdr->setup_sects == 0) +	hdr->setup_sects = 4; +    kern_offset = (hdr->setup_sects + 1) * 512; +    seek_io(fd, kern_offset); +    kern_size = file_size() - kern_offset; +    debug("offset=%#x addr=%#x size=%#x\n", kern_offset, kern_addr, kern_size); + +#if 0 +    if (using_devsize) { +	printf("Attempt to load up to end of device as kernel; " +		"specify the image size\n"); +	return 0; +    } +#endif + +    printf("Loading kernel... "); +    if ((uint32_t)read_io(fd, phys_to_virt(kern_addr), kern_size) != kern_size) { +	printf("Can't read kernel\n"); +	return 0; +    } +    printf("ok\n"); + +    return kern_size; +} + +static int load_initrd(struct linux_header *hdr, uint32_t kern_end, +                       struct linux_params *params, const char *initrd_file) +{ +    uint32_t max; +    uint32_t start, end, size; +    uint64_t forced; + +    fd = open_io(initrd_file); +    if (fd == -1) { +	printf("Can't open initrd: %s\n", initrd_file); +	return -1; +    } + +#if 0 +    if (using_devsize) { +	printf("Attempt to load up to end of device as initrd; " +		"specify the image size\n"); +	return -1; +    } +#endif + +    size = file_size(); + + +    /* Find out the kernel's restriction on how high the initrd can be +     * placed */ +    if (hdr->protocol_version >= 0x203) +	max = hdr->initrd_addr_max; +    else +	max = 0x38000000; /* Hardcoded value for older kernels */ + +    /* FILO itself is at the top of RAM. (relocated) +     * So, try putting initrd just below us. */ +    end = virt_to_phys(_start); +    if (end > max) +	end = max; + +    /* If "mem=" option is given, we have to put the initrd within +     * the specified range. */ +    if (forced_memsize) { +	forced = forced_memsize; +	if (forced > max) +	    forced = max; +	/* If the "mem=" is lower, it's easy */ +	if (forced <= end) +	    end = forced; +	else { +	    /* Otherwise, see if we can put it above us */ +	    if (virt_to_phys(_end) + size <= forced) +		end = forced; /* Ok */ +	} +    } + +    start = end - size; +    start &= ~0xfff; /* page align */ +    end = start + size; + +    debug("start=%#x end=%#x\n", start, end); + +    if (start < kern_end) { +	printf("Initrd is too big to fit in memory\n"); +	return -1; +    } + +    printf("Loading initrd... "); +    if ((uint32_t)read_io(fd, phys_to_virt(start), size) != size) { +	printf("Can't read initrd\n"); +	return -1; +    } +    printf("ok\n"); + +    params->initrd_start = start; +    params->initrd_size = size; + +    close_io(fd); + +    return 0; +} + +static void hardware_setup(void) +{ +    /* Disable nmi */ +    outb(0x80, 0x70); + +    /* Make sure any coprocessor is properly reset.. */ +    outb(0, 0xf0); +    outb(0, 0xf1); + +    /* we're getting screwed again and again by this problem of the 8259. +     * so we're going to leave this lying around for inclusion into +     * crt0.S on an as-needed basis. +     * +     * well, that went ok, I hope. Now we have to reprogram the interrupts :-( +     * we put them right after the intel-reserved hardware interrupts, at +     * int 0x20-0x2F. There they won't mess up anything. Sadly IBM really +     * messed this up with the original PC, and they haven't been able to +     * rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f, +     * which is used for the internal hardware interrupts as well. We just +     * have to reprogram the 8259's, and it isn't fun. +     */ + +    outb(0x11, 0x20);		/* initialization sequence to 8259A-1 */ +    outb(0x11, 0xA0);		/* and to 8259A-2 */ + +    outb(0x20, 0x21);		/* start of hardware int's (0x20) */ +    outb(0x28, 0xA1);		/* start of hardware int's 2 (0x28) */ + +    outb(0x04, 0x21);		/* 8259-1 is master */ +    outb(0x02, 0xA1);		/* 8259-2 is slave */ + +    outb(0x01, 0x21);		/* 8086 mode for both */ +    outb(0x01, 0xA1); + +    outb(0xFF, 0xA1);		/* mask off all interrupts for now */ +    outb(0xFB, 0x21);		/* mask all irq's but irq2 which is cascaded */ +} + +/* Start Linux */ +static int start_linux(uint32_t kern_addr) +{ +    struct context *ctx; +    //extern int cursor_x, cursor_y; + +    ctx = init_context(phys_to_virt(STACK_LOC), 4096, 0); + +    /* Entry point */ +    ctx->pc = kern_addr; +    ctx->npc = kern_addr + 4; + +    debug("pc=%#x\n", kern_addr); +    printf("Jumping to entry point...\n"); + +#ifdef VGA_CONSOLE +    /* Update VGA cursor position. +     * This must be here because the printf changes the value! */ +    params->orig_x = cursor_x; +    params->orig_y = cursor_y; +#endif + +    /* Go... */ +    ctx = switch_to(ctx); + +    /* It's impossible but... */ +    printf("Returned with o0=%#x\n", ctx->regs[REG_O0]); + +    return ctx->regs[REG_O0]; +} + +int linux_load(struct sys_info *info, const char *file, const char *cmdline) +{ +    struct linux_header hdr; +    struct linux_params *params; +    uint32_t kern_addr, kern_size; +    char *initrd_file = NULL; + +    fd = open_io(file); +    if (fd == -1) { +	return -1; +    } + +    kern_addr = load_linux_header(&hdr); +    if (kern_addr == 0) { +	close_io(fd); +	return LOADER_NOT_SUPPORT; +    } + +    params = phys_to_virt(LINUX_PARAM_LOC); +    init_linux_params(params, &hdr); +    set_memory_size(params, info); +    initrd_file = parse_command_line(cmdline, phys_to_virt(COMMAND_LINE_LOC)); +    set_command_line_loc(params, &hdr); + +    kern_size = load_linux_kernel(&hdr, kern_addr); +    if (kern_size == 0) { +	if (initrd_file) +	    free(initrd_file); +	return -1; +    } + +    if (initrd_file) { +        if (load_initrd(&hdr, kern_addr+kern_size, params, initrd_file) +		!= 0) { +	    free(initrd_file); +	    return -1; +	} +	free(initrd_file); +    } + +    hardware_setup(); + +    start_linux(kern_addr); +    return 0; +} diff --git a/roms/openbios/arch/sparc32/multiboot.c b/roms/openbios/arch/sparc32/multiboot.c new file mode 100644 index 00000000..8514ca0a --- /dev/null +++ b/roms/openbios/arch/sparc32/multiboot.c @@ -0,0 +1,125 @@ +/* Support for Multiboot */ + +#include "config.h" +#include "asm/io.h" +#include "libopenbios/sys_info.h" +#include "multiboot.h" + +#define printf printk +#ifdef CONFIG_DEBUG_BOOT +#define debug printk +#else +#define debug(x...) +#endif + +struct mbheader { +    unsigned int magic, flags, checksum; +}; +const struct mbheader multiboot_header +	__attribute__((section (".hdr"))) = +{ +    MULTIBOOT_HEADER_MAGIC, +    MULTIBOOT_HEADER_FLAGS, +    -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) +}; + +/* Multiboot information structure, provided by loader to us */ + +struct multiboot_mmap { +	unsigned entry_size; +	unsigned base_lo, base_hi; +	unsigned size_lo, size_hi; +	unsigned type; +}; + +#define MULTIBOOT_MEM_VALID       0x01 +#define MULTIBOOT_BOOT_DEV_VALID  0x02 +#define MULTIBOOT_CMDLINE_VALID   0x04 +#define MULTIBOOT_MODS_VALID      0x08 +#define MULTIBOOT_AOUT_SYMS_VALID 0x10 +#define MULTIBOOT_ELF_SYMS_VALID  0x20 +#define MULTIBOOT_MMAP_VALID      0x40 + +void collect_multiboot_info(struct sys_info *info); +void collect_multiboot_info(struct sys_info *info) +{ +    struct multiboot_info *mbinfo; +    struct multiboot_mmap *mbmem; +    unsigned mbcount, mbaddr; +    unsigned int i; +    struct memrange *mmap; +    int mmap_count; +    module_t *mod; + +    if (info->boot_type != 0x2BADB002) +	return; + +    debug("Using Multiboot information at %#lx\n", info->boot_data); + +    mbinfo = phys_to_virt(info->boot_data); + +    if (mbinfo->mods_count != 1) { +	    printf("Multiboot: no dictionary\n"); +	    return; +    } + +    mod = (module_t *) mbinfo->mods_addr; +    info->dict_start=(unsigned long *)mod->mod_start; +    info->dict_end=(unsigned long *)mod->mod_end; + +    if (mbinfo->flags & MULTIBOOT_MMAP_VALID) { +	/* convert mmap records */ +	mbmem = phys_to_virt(mbinfo->mmap_addr); +	mbcount = mbinfo->mmap_length / (mbmem->entry_size + 4); +	mmap = malloc(mbcount * sizeof(struct memrange)); +	mmap_count = 0; +	mbaddr = mbinfo->mmap_addr; +	for (i = 0; i < mbcount; i++) { +	    mbmem = phys_to_virt(mbaddr); +	    debug("%08x%08x %08x%08x (%d)\n", +		    mbmem->base_hi, +		    mbmem->base_lo, +		    mbmem->size_hi, +		    mbmem->size_lo, +		    mbmem->type); +	    if (mbmem->type == 1) { /* Only normal RAM */ +		mmap[mmap_count].base = mbmem->base_lo +		    + (((unsigned long long) mbmem->base_hi) << 32); +		mmap[mmap_count].size = mbmem->size_lo +		    + (((unsigned long long) mbmem->size_hi) << 32); +		mmap_count++; +	    } +	    mbaddr += mbmem->entry_size + 4; +	    if (mbaddr >= mbinfo->mmap_addr + mbinfo->mmap_length) +		break; +	} +	/* simple sanity check - there should be at least 2 RAM segments +	 * (base 640k and extended) */ +	if (mmap_count >= 2) +	    goto got_it; + +	printf("Multiboot mmap is broken\n"); +	free(mmap); +	/* fall back to mem_lower/mem_upper */ +    } + +    if (mbinfo->flags & MULTIBOOT_MEM_VALID) { +	/* use mem_lower and mem_upper */ +	mmap_count = 2; +	mmap = malloc(2 * sizeof(*mmap)); +	mmap[0].base = 0; +	mmap[0].size = mbinfo->mem_lower << 10; +	mmap[1].base = 1 << 20; /* 1MB */ +	mmap[1].size = mbinfo->mem_upper << 10; +	goto got_it; +    } + +    printf("Can't get memory information from Multiboot\n"); +    return; + +got_it: +    info->memrange = mmap; +    info->n_memranges = mmap_count; + +    return; +} diff --git a/roms/openbios/arch/sparc32/multiboot.h b/roms/openbios/arch/sparc32/multiboot.h new file mode 100644 index 00000000..17cf202e --- /dev/null +++ b/roms/openbios/arch/sparc32/multiboot.h @@ -0,0 +1,96 @@ +/* multiboot.h + * tag: header for multiboot + * + * Copyright (C) 2003-2004 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +/* magic number for multiboot header */ +#define MULTIBOOT_HEADER_MAGIC		0x1BADB002 + +/* flags for multiboot header */ +#define MULTIBOOT_HEADER_FLAGS		0x00010003 + +/* magic number passed by multiboot-compliant boot loader.  */ +#define MULTIBOOT_BOOTLOADER_MAGIC	0x2BADB002 + +/* The size of our stack (8KB).  */ +#define STACK_SIZE			0x2000 + +/* C symbol format. HAVE_ASM_USCORE is defined by configure.  */ +#ifdef HAVE_ASM_USCORE +# define EXT_C(sym)			_ ## sym +#else +# define EXT_C(sym)			sym +#endif + +#ifndef ASM +/* We don't want these declarations in boot.S  */ + +/* multiboot header */ +typedef struct multiboot_header { +	unsigned long magic; +	unsigned long flags; +	unsigned long checksum; +	unsigned long header_addr; +	unsigned long load_addr; +	unsigned long load_end_addr; +	unsigned long bss_end_addr; +	unsigned long entry_addr; +} multiboot_header_t; + +/* symbol table for a.out */ +typedef struct aout_symbol_table { +	unsigned long tabsize; +	unsigned long strsize; +	unsigned long addr; +	unsigned long reserved; +} aout_symbol_table_t; + +/* section header table for ELF */ +typedef struct elf_section_header_table { +	unsigned long num; +	unsigned long size; +	unsigned long addr; +	unsigned long shndx; +} elf_section_header_table_t; + +/* multiboot information */ +typedef struct multiboot_info { +	unsigned long flags; +	unsigned long mem_lower; +	unsigned long mem_upper; +	unsigned long boot_device; +	unsigned long cmdline; +	unsigned long mods_count; +	unsigned long mods_addr; +	union { +		aout_symbol_table_t aout_sym; +		elf_section_header_table_t elf_sec; +	} u; +	unsigned long mmap_length; +	unsigned long mmap_addr; +} multiboot_info_t; + +/* module structure */ +typedef struct module { +	unsigned long mod_start; +	unsigned long mod_end; +	unsigned long string; +	unsigned long reserved; +} module_t; + +/* memory map. Be careful that the offset 0 is base_addr_low +   but no size.  */ +typedef struct memory_map { +	unsigned long size; +	unsigned long base_addr_low; +	unsigned long base_addr_high; +	unsigned long length_low; +	unsigned long length_high; +	unsigned long type; +} memory_map_t; + +#endif				/* ! ASM */ diff --git a/roms/openbios/arch/sparc32/ofmem_sparc32.c b/roms/openbios/arch/sparc32/ofmem_sparc32.c new file mode 100644 index 00000000..f7af7536 --- /dev/null +++ b/roms/openbios/arch/sparc32/ofmem_sparc32.c @@ -0,0 +1,253 @@ +/* + *	<ofmem_sparc32.c> + * + *	OF Memory manager + * + *   Copyright (C) 1999-2004 Samuel Rydh (samuel@ibrium.se) + *   Copyright (C) 2004 Stefan Reinauer + * + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License + *   as published by the Free Software Foundation + * + */ + +#include "config.h" +#include "libopenbios/bindings.h" +#include "libc/string.h" +#include "arch/sparc32/ofmem_sparc32.h" +#include "asm/asi.h" +#include "pgtsrmmu.h" + +#define OF_MALLOC_BASE		((char*)OFMEM + ALIGN_SIZE(sizeof(ofmem_t), 8)) + +#define MEMSIZE (256 * 1024) +static union { +	char memory[MEMSIZE]; +	ofmem_t ofmem; +} s_ofmem_data; + +#define OFMEM      	(&s_ofmem_data.ofmem) +#define TOP_OF_RAM 	(s_ofmem_data.memory + MEMSIZE) + +#define OFMEM_PHYS_RESERVED	0x1000000 + +translation_t **g_ofmem_translations = &s_ofmem_data.ofmem.trans; + +extern uint32_t qemu_mem_size; + +static inline size_t ALIGN_SIZE(size_t x, size_t a) +{ +    return (x + a - 1) & ~(a-1); +} + +static ucell get_heap_top( void ) +{ +	return (ucell)TOP_OF_RAM; +} + +ofmem_t* ofmem_arch_get_private(void) +{ +	return OFMEM; +} + +void* ofmem_arch_get_malloc_base(void) +{ +	return OF_MALLOC_BASE; +} + +ucell ofmem_arch_get_heap_top(void) +{ +	return get_heap_top(); +} + +ucell ofmem_arch_get_virt_top(void) +{ +	return (ucell)OFMEM_VIRT_TOP; +} + +ucell ofmem_arch_get_iomem_base(void) +{ +	return pointer2cell(&_end); +} + +ucell ofmem_arch_get_iomem_top(void) +{ +	return pointer2cell(&_iomem); +} + +retain_t *ofmem_arch_get_retained(void) +{ +	/* Not used */ +	return 0; +} + +int ofmem_arch_get_physaddr_cellsize(void) +{ +	return 2; +} + +int ofmem_arch_encode_physaddr(ucell *p, phys_addr_t value) +{ +	int n = 0; + +	p[n++] = value >> 32; +	p[n++] = value; + +	return n; +} + +int ofmem_arch_get_translation_entry_size(void) +{ +	/* Return size of a single MMU package translation property entry in cells */ +	return 3; +} + +void ofmem_arch_create_translation_entry(ucell *transentry, translation_t *t) +{ +	/* Generate translation property entry for SPARC. While there is no +	formal documentation for this, both Linux kernel and OpenSolaris sources +	expect a translation property entry to have the following layout: + +		virtual address +		length +		mode +	*/ + +	transentry[0] = t->virt; +	transentry[1] = t->size; +	transentry[2] = t->mode; +} + +/* Return the size of a memory available entry given the phandle in cells */ +int ofmem_arch_get_available_entry_size(phandle_t ph) +{ +	return 1 + ofmem_arch_get_physaddr_cellsize(); +} + +/* Generate memory available property entry for Sparc32 */ +void ofmem_arch_create_available_entry(phandle_t ph, ucell *availentry, phys_addr_t start, ucell size) +{ +  int i = 0; + +	i += ofmem_arch_encode_physaddr(availentry, start); +	availentry[i] = size; +} + +/* Unmap a set of pages */ +void ofmem_arch_unmap_pages(ucell virt, ucell size) +{ +	unsigned long pa; +	ucell i; + +	for (i = 0; i < size; i += PAGE_SIZE) { +		pa = find_pte(virt, 0); +		*(uint32_t *)pa = 0; +		virt += PAGE_SIZE; +	} + +	srmmu_flush_whole_tlb();  +} + +/* Map a set of pages */ +void ofmem_arch_map_pages(phys_addr_t phys, ucell virt, ucell size, ucell mode) +{ +	unsigned long npages, off; +	uint32_t pte; +	unsigned long pa; + +	off = phys & (PAGE_SIZE - 1); +	npages = (off + (size - 1) + (PAGE_SIZE - 1)) / PAGE_SIZE; +	phys &= ~(uint64_t)(PAGE_SIZE - 1); + +	while (npages-- != 0) { +		pa = find_pte(virt, 1); + +		pte = SRMMU_ET_PTE | ((phys & PAGE_MASK) >> 4); +		pte |= mode; + +		*(uint32_t *)pa = pte; + +		virt += PAGE_SIZE; +		phys += PAGE_SIZE; +	} +} + +/* Architecture-specific OFMEM helpers */ +unsigned long +find_pte(unsigned long va, int alloc) +{ +    uint32_t pte; +    void *p; +    unsigned long pa; +    int ret; + +    pte = l1[(va >> SRMMU_PGDIR_SHIFT) & (SRMMU_PTRS_PER_PGD - 1)]; +    if ((pte & SRMMU_ET_MASK) == SRMMU_ET_INVALID) { +        if (alloc) { +            ret = ofmem_posix_memalign(&p, SRMMU_PTRS_PER_PMD * sizeof(int), +                                 SRMMU_PTRS_PER_PMD * sizeof(int)); +            if (ret != 0) +                return ret; +            pte = SRMMU_ET_PTD | ((va2pa((unsigned long)p)) >> 4); +            l1[(va >> SRMMU_PGDIR_SHIFT) & (SRMMU_PTRS_PER_PGD - 1)] = pte; +            /* barrier() */ +        } else { +            return -1; +        } +    } + +    pa = (pte & 0xFFFFFFF0) << 4; +    pa += ((va >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1)) << 2; +    pte = *(uint32_t *)pa2va(pa); +    if ((pte & SRMMU_ET_MASK) == SRMMU_ET_INVALID) { +        if (alloc) { +            ret = ofmem_posix_memalign(&p, SRMMU_PTRS_PER_PTE * sizeof(void *), +                                 SRMMU_PTRS_PER_PTE * sizeof(void *)); +            if (ret != 0) +                return ret; +            pte = SRMMU_ET_PTD | ((va2pa((unsigned int)p)) >> 4); +            *(uint32_t *)pa2va(pa) = pte; +        } else { +            return -2; +        } +    } + +    pa = (pte & 0xFFFFFFF0) << 4; +    pa += ((va >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1)) << 2; + +    return pa2va(pa); +} + +/************************************************************************/ +/* misc                                                                 */ +/************************************************************************/ + +ucell ofmem_arch_default_translation_mode( phys_addr_t phys ) +{ +	return SRMMU_REF | SRMMU_CACHE | SRMMU_PRIV; +} + +ucell ofmem_arch_io_translation_mode( phys_addr_t phys ) +{ +	return SRMMU_REF | SRMMU_PRIV; +} + +/************************************************************************/ +/* init / cleanup                                                       */ +/************************************************************************/ + +void ofmem_init( void ) +{ +	memset(&s_ofmem_data, 0, sizeof(s_ofmem_data)); +	s_ofmem_data.ofmem.ramsize = qemu_mem_size; +	 +	/* Mark the first page as non-free */ +	ofmem_claim_virt(0, PAGE_SIZE, 0); +	 +	/* Claim reserved physical addresses at top of RAM */ +	ofmem_claim_phys(s_ofmem_data.ofmem.ramsize - OFMEM_PHYS_RESERVED, OFMEM_PHYS_RESERVED, 0); +	 +	/* Claim OpenBIOS reserved space */ +	ofmem_claim_virt(0xffd00000, 0x200000, 0); +} diff --git a/roms/openbios/arch/sparc32/openbios.c b/roms/openbios/arch/sparc32/openbios.c new file mode 100644 index 00000000..6f4ee454 --- /dev/null +++ b/roms/openbios/arch/sparc32/openbios.c @@ -0,0 +1,1005 @@ +/* tag: openbios forth environment, executable code + * + * Copyright (C) 2003 Patrick Mauritz, Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#include "config.h" +#include "libopenbios/openbios.h" +#include "libopenbios/bindings.h" +#include "libopenbios/console.h" +#include "drivers/drivers.h" +#include "asm/types.h" +#include "dict.h" +#include "kernel/kernel.h" +#include "kernel/stack.h" +#include "arch/common/nvram.h" +#include "packages/nvram.h" +#include "../../drivers/timer.h" // XXX +#include "libopenbios/sys_info.h" +#include "openbios.h" +#include "boot.h" +#include "romvec.h" +#include "openprom.h" +#include "psr.h" +#include "libopenbios/video.h" +#define NO_QEMU_PROTOS +#include "arch/common/fw_cfg.h" +#include "arch/sparc32/ofmem_sparc32.h" + +#define MEMORY_SIZE     (128*1024)       /* 128K ram for hosted system */ +#define UUID_FMT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" +#define FW_CFG_SUN4M_DEPTH   (FW_CFG_ARCH_LOCAL + 0x00) + +int qemu_machine_type; + +struct hwdef { +    uint64_t iommu_base, slavio_base; +    uint64_t intctl_base, counter_base, nvram_base, ms_kb_base, serial_base; +    unsigned long fd_offset, counter_offset, intr_offset; +    unsigned long aux1_offset, aux2_offset; +    uint64_t dma_base, esp_base, le_base; +    uint64_t tcx_base; +    int intr_ncpu; +    int mid_offset; +    int machine_id_low, machine_id_high; +}; + +static const struct hwdef hwdefs[] = { +    /* SS-5 */ +    { +        .iommu_base   = 0x10000000, +        .tcx_base     = 0x50000000, +        .slavio_base  = 0x71000000, +        .ms_kb_base   = 0x71000000, +        .serial_base  = 0x71100000, +        .nvram_base   = 0x71200000, +        .fd_offset    = 0x00400000, +        .counter_offset = 0x00d00000, +        .intr_offset  = 0x00e00000, +        .intr_ncpu    = 1, +        .aux1_offset  = 0x00900000, +        .aux2_offset  = 0x00910000, +        .dma_base     = 0x78400000, +        .esp_base     = 0x78800000, +        .le_base      = 0x78c00000, +        .mid_offset   = 0, +        .machine_id_low = 32, +        .machine_id_high = 63, +    }, +    /* SS-10, SS-20 */ +    { +        .iommu_base   = 0xfe0000000ULL, +        .tcx_base     = 0xe20000000ULL, +        .slavio_base  = 0xff1000000ULL, +        .ms_kb_base   = 0xff1000000ULL, +        .serial_base  = 0xff1100000ULL, +        .nvram_base   = 0xff1200000ULL, +        .fd_offset    = 0x00700000, // 0xff1700000ULL, +        .counter_offset = 0x00300000, // 0xff1300000ULL, +        .intr_offset  = 0x00400000, // 0xff1400000ULL, +        .intr_ncpu    = 4, +        .aux1_offset  = 0x00800000, // 0xff1800000ULL, +        .aux2_offset  = 0x00a01000, // 0xff1a01000ULL, +        .dma_base     = 0xef0400000ULL, +        .esp_base     = 0xef0800000ULL, +        .le_base      = 0xef0c00000ULL, +        .mid_offset   = 8, +        .machine_id_low = 64, +        .machine_id_high = 65, +    }, +    /* SS-600MP */ +    { +        .iommu_base   = 0xfe0000000ULL, +        .tcx_base     = 0xe20000000ULL, +        .slavio_base  = 0xff1000000ULL, +        .ms_kb_base   = 0xff1000000ULL, +        .serial_base  = 0xff1100000ULL, +        .nvram_base   = 0xff1200000ULL, +        .fd_offset    = -1, +        .counter_offset = 0x00300000, // 0xff1300000ULL, +        .intr_offset  = 0x00400000, // 0xff1400000ULL, +        .intr_ncpu    = 4, +        .aux1_offset  = 0x00800000, // 0xff1800000ULL, +        .aux2_offset  = 0x00a01000, // 0xff1a01000ULL, XXX should not exist +        .dma_base     = 0xef0081000ULL, +        .esp_base     = 0xef0080000ULL, +        .le_base      = 0xef0060000ULL, +        .mid_offset   = 8, +        .machine_id_low = 66, +        .machine_id_high = 66, +    }, +}; + +static const struct hwdef *hwdef; + +void setup_timers(void) +{ +} + +void udelay(unsigned int usecs) +{ +} + +void mdelay(unsigned int msecs) +{ +} + +static void mb86904_init(void) +{ +    PUSH(32); +    fword("encode-int"); +    push_str("cache-line-size"); +    fword("property"); + +    PUSH(512); +    fword("encode-int"); +    push_str("cache-nlines"); +    fword("property"); + +    PUSH(0x23); +    fword("encode-int"); +    push_str("mask_rev"); +    fword("property"); +} + +static void tms390z55_init(void) +{ +    push_str(""); +    fword("encode-string"); +    push_str("ecache-parity?"); +    fword("property"); + +    push_str(""); +    fword("encode-string"); +    push_str("bfill?"); +    fword("property"); + +    push_str(""); +    fword("encode-string"); +    push_str("bcopy?"); +    fword("property"); + +    push_str(""); +    fword("encode-string"); +    push_str("cache-physical?"); +    fword("property"); + +    PUSH(0xf); +    fword("encode-int"); +    PUSH(0xf8fffffc); +    fword("encode-int"); +    fword("encode+"); +    PUSH(4); +    fword("encode-int"); +    fword("encode+"); + +    PUSH(0xf); +    fword("encode-int"); +    fword("encode+"); +    PUSH(0xf8c00000); +    fword("encode-int"); +    fword("encode+"); +    PUSH(0x1000); +    fword("encode-int"); +    fword("encode+"); + +    PUSH(0xf); +    fword("encode-int"); +    fword("encode+"); +    PUSH(0xf8000000); +    fword("encode-int"); +    fword("encode+"); +    PUSH(0x1000); +    fword("encode-int"); +    fword("encode+"); + +    PUSH(0xf); +    fword("encode-int"); +    fword("encode+"); +    PUSH(0xf8800000); +    fword("encode-int"); +    fword("encode+"); +    PUSH(0x1000); +    fword("encode-int"); +    fword("encode+"); +    push_str("reg"); +    fword("property"); +} + +static void rt625_init(void) +{ +    PUSH(32); +    fword("encode-int"); +    push_str("cache-line-size"); +    fword("property"); + +    PUSH(512); +    fword("encode-int"); +    push_str("cache-nlines"); +    fword("property"); + +} + +static void bad_cpu_init(void) +{ +    printk("This CPU is not supported yet, freezing.\n"); +    for(;;); +} + +struct cpudef { +    unsigned long iu_version; +    const char *name; +    int psr_impl, psr_vers, impl, vers; +    int dcache_line_size, dcache_lines, dcache_assoc; +    int icache_line_size, icache_lines, icache_assoc; +    int ecache_line_size, ecache_lines, ecache_assoc; +    int mmu_nctx; +    void (*initfn)(void); +}; + +static const struct cpudef sparc_defs[] = { +    { +        .iu_version = 0x00 << 24, /* Impl 0, ver 0 */ +        .name = "FMI,MB86900", +        .initfn = bad_cpu_init, +    }, +    { +        .iu_version = 0x04 << 24, /* Impl 0, ver 4 */ +        .name = "FMI,MB86904", +        .psr_impl = 0, +        .psr_vers = 4, +        .impl = 0, +        .vers = 4, +        .dcache_line_size = 0x10, +        .dcache_lines = 0x200, +        .dcache_assoc = 1, +        .icache_line_size = 0x20, +        .icache_lines = 0x200, +        .icache_assoc = 1, +        .ecache_line_size = 0x20, +        .ecache_lines = 0x4000, +        .ecache_assoc = 1, +        .mmu_nctx = 0x100, +        .initfn = mb86904_init, +    }, +    { +        .iu_version = 0x05 << 24, /* Impl 0, ver 5 */ +        .name = "FMI,MB86907", +        .psr_impl = 0, +        .psr_vers = 5, +        .impl = 0, +        .vers = 5, +        .dcache_line_size = 0x20, +        .dcache_lines = 0x200, +        .dcache_assoc = 1, +        .icache_line_size = 0x20, +        .icache_lines = 0x200, +        .icache_assoc = 1, +        .ecache_line_size = 0x20, +        .ecache_lines = 0x4000, +        .ecache_assoc = 1, +        .mmu_nctx = 0x100, +        .initfn = mb86904_init, +    }, +    { +        .iu_version = 0x10 << 24, /* Impl 1, ver 0 */ +        .name = "LSI,L64811", +        .initfn = bad_cpu_init, +    }, +    { +        .iu_version = 0x11 << 24, /* Impl 1, ver 1 */ +        .name = "CY,CY7C601", +        .psr_impl = 1, +        .psr_vers = 1, +        .impl = 1, +        .vers = 1, +        .mmu_nctx = 0x10, +        .initfn = bad_cpu_init, +    }, +    { +        .iu_version = 0x13 << 24, /* Impl 1, ver 3 */ +        .name = "CY,CY7C611", +        .initfn = bad_cpu_init, +    }, +    { +        .iu_version = 0x40000000, +        .name = "TI,TMS390Z55", +        .psr_impl = 4, +        .psr_vers = 0, +        .impl = 0, +        .vers = 4, +        .dcache_line_size = 0x20, +        .dcache_lines = 0x80, +        .dcache_assoc = 4, +        .icache_line_size = 0x40, +        .icache_lines = 0x40, +        .icache_assoc = 5, +        .ecache_line_size = 0x20, +        .ecache_lines = 0x8000, +        .ecache_assoc = 1, +        .mmu_nctx = 0x10000, +        .initfn = tms390z55_init, +    }, +    { +        .iu_version = 0x41000000, +        .name = "TI,TMS390S10", +        .psr_impl = 4, +        .psr_vers = 1, +        .impl = 4, +        .vers = 1, +        .dcache_line_size = 0x10, +        .dcache_lines = 0x80, +        .dcache_assoc = 4, +        .icache_line_size = 0x20, +        .icache_lines = 0x80, +        .icache_assoc = 5, +        .ecache_line_size = 0x20, +        .ecache_lines = 0x8000, +        .ecache_assoc = 1, +        .mmu_nctx = 0x10000, +        .initfn = tms390z55_init, +    }, +    { +        .iu_version = 0x42000000, +        .name = "TI,TMS390S10", +        .psr_impl = 4, +        .psr_vers = 2, +        .impl = 4, +        .vers = 2, +        .dcache_line_size = 0x10, +        .dcache_lines = 0x80, +        .dcache_assoc = 4, +        .icache_line_size = 0x20, +        .icache_lines = 0x80, +        .icache_assoc = 5, +        .ecache_line_size = 0x20, +        .ecache_lines = 0x8000, +        .ecache_assoc = 1, +        .mmu_nctx = 0x10000, +        .initfn = tms390z55_init, +    }, +    { +        .iu_version = 0x43000000, +        .name = "TI,TMS390S10", +        .psr_impl = 4, +        .psr_vers = 3, +        .impl = 4, +        .vers = 3, +        .dcache_line_size = 0x10, +        .dcache_lines = 0x80, +        .dcache_assoc = 4, +        .icache_line_size = 0x20, +        .icache_lines = 0x80, +        .icache_assoc = 5, +        .ecache_line_size = 0x20, +        .ecache_lines = 0x8000, +        .ecache_assoc = 1, +        .mmu_nctx = 0x10000, +        .initfn = tms390z55_init, +    }, +    { +        .iu_version = 0x44000000, +        .name = "TI,TMS390S10", +        .psr_impl = 4, +        .psr_vers = 4, +        .impl = 4, +        .vers = 4, +        .dcache_line_size = 0x10, +        .dcache_lines = 0x80, +        .dcache_assoc = 4, +        .icache_line_size = 0x20, +        .icache_lines = 0x80, +        .icache_assoc = 5, +        .ecache_line_size = 0x20, +        .ecache_lines = 0x8000, +        .ecache_assoc = 1, +        .mmu_nctx = 0x10000, +        .initfn = tms390z55_init, +    }, +    { +        .iu_version = 0x1e000000, +        .name = "Ross,RT625", +        .psr_impl = 1, +        .psr_vers = 14, +        .impl = 1, +        .vers = 7, +        .dcache_line_size = 0x20, +        .dcache_lines = 0x80, +        .dcache_assoc = 4, +        .icache_line_size = 0x40, +        .icache_lines = 0x40, +        .icache_assoc = 5, +        .ecache_line_size = 0x20, +        .ecache_lines = 0x8000, +        .ecache_assoc = 1, +        .mmu_nctx = 0x10000, +        .initfn = rt625_init, +    }, +    { +        .iu_version = 0x1f000000, +        .name = "Ross,RT620", +        .psr_impl = 1, +        .psr_vers = 15, +        .impl = 1, +        .vers = 7, +        .dcache_line_size = 0x20, +        .dcache_lines = 0x80, +        .dcache_assoc = 4, +        .icache_line_size = 0x40, +        .icache_lines = 0x40, +        .icache_assoc = 5, +        .ecache_line_size = 0x20, +        .ecache_lines = 0x8000, +        .ecache_assoc = 1, +        .mmu_nctx = 0x10000, +        .initfn = rt625_init, +    }, +    { +        .iu_version = 0x20000000, +        .name = "BIT,B5010", +        .initfn = bad_cpu_init, +    }, +    { +        .iu_version = 0x50000000, +        .name = "MC,MN10501", +        .initfn = bad_cpu_init, +    }, +    { +        .iu_version = 0x90 << 24, /* Impl 9, ver 0 */ +        .name = "Weitek,W8601", +        .initfn = bad_cpu_init, +    }, +    { +        .iu_version = 0xf2000000, +        .name = "GR,LEON2", +        .initfn = bad_cpu_init, +    }, +    { +        .iu_version = 0xf3000000, +        .name = "GR,LEON3", +        .initfn = bad_cpu_init, +    }, +}; + +static const struct cpudef * +id_cpu(void) +{ +    unsigned long iu_version; +    unsigned int i; + +    asm("rd %%psr, %0\n" +        : "=r"(iu_version) :); +    iu_version &= 0xff000000; + +    for (i = 0; i < sizeof(sparc_defs)/sizeof(struct cpudef); i++) { +        if (iu_version == sparc_defs[i].iu_version) +            return &sparc_defs[i]; +    } +    printk("Unknown cpu (psr %lx), freezing!\n", iu_version); +    for (;;); +} + +static void setup_cpu(int mid_offset) +{ +    uint32_t temp; +    unsigned int i; +    const struct cpudef *cpu; + +    // Add cpus +    temp = fw_cfg_read_i32(FW_CFG_NB_CPUS); + +    printk("CPUs: %x", temp); +    cpu = id_cpu(); +    printk(" x %s\n", cpu->name); +    for (i = 0; i < temp; i++) { +        push_str("/"); +        fword("find-device"); + +        fword("new-device"); + +        push_str(cpu->name); +        fword("device-name"); + +        push_str("cpu"); +        fword("device-type"); + +        PUSH(cpu->psr_impl); +        fword("encode-int"); +        push_str("psr-implementation"); +        fword("property"); + +        PUSH(cpu->psr_vers); +        fword("encode-int"); +        push_str("psr-version"); +        fword("property"); + +        PUSH(cpu->impl); +        fword("encode-int"); +        push_str("implementation"); +        fword("property"); + +        PUSH(cpu->vers); +        fword("encode-int"); +        push_str("version"); +        fword("property"); + +        PUSH(4096); +        fword("encode-int"); +        push_str("page-size"); +        fword("property"); + +        PUSH(cpu->dcache_line_size); +        fword("encode-int"); +        push_str("dcache-line-size"); +        fword("property"); + +        PUSH(cpu->dcache_lines); +        fword("encode-int"); +        push_str("dcache-nlines"); +        fword("property"); + +        PUSH(cpu->dcache_assoc); +        fword("encode-int"); +        push_str("dcache-associativity"); +        fword("property"); + +        PUSH(cpu->icache_line_size); +        fword("encode-int"); +        push_str("icache-line-size"); +        fword("property"); + +        PUSH(cpu->icache_lines); +        fword("encode-int"); +        push_str("icache-nlines"); +        fword("property"); + +        PUSH(cpu->icache_assoc); +        fword("encode-int"); +        push_str("icache-associativity"); +        fword("property"); + +        PUSH(cpu->ecache_line_size); +        fword("encode-int"); +        push_str("ecache-line-size"); +        fword("property"); + +        PUSH(cpu->ecache_lines); +        fword("encode-int"); +        push_str("ecache-nlines"); +        fword("property"); + +        PUSH(cpu->ecache_assoc); +        fword("encode-int"); +        push_str("ecache-associativity"); +        fword("property"); + +        PUSH(2); +        fword("encode-int"); +        push_str("ncaches"); +        fword("property"); + +        PUSH(cpu->mmu_nctx); +        fword("encode-int"); +        push_str("mmu-nctx"); +        fword("property"); + +        PUSH(8); +        fword("encode-int"); +        push_str("sparc-version"); +        fword("property"); + +        push_str(""); +        fword("encode-string"); +        push_str("cache-coherence?"); +        fword("property"); + +        PUSH(i + mid_offset); +        fword("encode-int"); +        push_str("mid"); +        fword("property"); + +        cpu->initfn(); + +        fword("finish-device"); +    } +} + +static void dummy_mach_init(uint64_t base) +{ +} + +struct machdef { +    uint16_t machine_id; +    const char *banner_name; +    const char *model; +    const char *name; +    void (*initfn)(uint64_t base); +}; + +static const struct machdef sun4m_defs[] = { +    { +        .machine_id = 32, +        .banner_name = "SPARCstation 5", +        .model = "SUNW,501-3059", +        .name = "SUNW,SPARCstation-5", +        .initfn = ss5_init, +    }, +    { +        .machine_id = 33, +        .banner_name = "SPARCstation Voyager", +        .model = "SUNW,501-2581", +        .name = "SUNW,SPARCstation-Voyager", +        .initfn = dummy_mach_init, +    }, +    { +        .machine_id = 34, +        .banner_name = "SPARCstation LX", +        .model = "SUNW,501-2031", +        .name = "SUNW,SPARCstation-LX", +        .initfn = dummy_mach_init, +    }, +    { +        .machine_id = 35, +        .banner_name = "SPARCstation 4", +        .model = "SUNW,501-2572", +        .name = "SUNW,SPARCstation-4", +        .initfn = ss5_init, +    }, +    { +        .machine_id = 36, +        .banner_name = "SPARCstation Classic", +        .model = "SUNW,501-2326", +        .name = "SUNW,SPARCstation-Classic", +        .initfn = dummy_mach_init, +    }, +    { +        .machine_id = 37, +        .banner_name = "Tadpole S3 GX", +        .model = "S3", +        .name = "Tadpole_S3GX", +        .initfn = ss5_init, +    }, +    { +        .machine_id = 64, +        .banner_name = "SPARCstation 10 (1 X 390Z55)", +        .model = "SUNW,S10,501-2365", +        .name = "SUNW,SPARCstation-10", +        .initfn = ob_eccmemctl_init, +    }, +    { +        .machine_id = 65, +        .banner_name = "SPARCstation 20 (1 X 390Z55)", +        .model = "SUNW,S20,501-2324", +        .name = "SUNW,SPARCstation-20", +        .initfn = ob_eccmemctl_init, +    }, +    { +        .machine_id = 66, +        .banner_name = "SPARCsystem 600(1 X 390Z55)", +        .model = NULL, +        .name = "SUNW,SPARCsystem-600", +        .initfn = ob_eccmemctl_init, +    }, +}; + +static const struct machdef * +id_machine(uint16_t machine_id) +{ +    unsigned int i; + +    for (i = 0; i < sizeof(sun4m_defs)/sizeof(struct machdef); i++) { +        if (machine_id == sun4m_defs[i].machine_id) +            return &sun4m_defs[i]; +    } +    printk("Unknown machine (ID %d), freezing!\n", machine_id); +    for (;;); +} + +static void setup_machine(uint64_t base) +{ +    uint16_t machine_id; +    const struct machdef *mach; + +    machine_id = fw_cfg_read_i16(FW_CFG_MACHINE_ID); +    mach = id_machine(machine_id); + +    push_str("/"); +    fword("find-device"); +    push_str(mach->banner_name); +    fword("encode-string"); +    push_str("banner-name"); +    fword("property"); + +    if (mach->model) { +        push_str(mach->model); +        fword("encode-string"); +        push_str("model"); +        fword("property"); +    } +    push_str(mach->name); +    fword("encode-string"); +    push_str("name"); +    fword("property"); + +    mach->initfn(base); +} + +/* Add /uuid */ +static void setup_uuid(void) +{ +    static uint8_t qemu_uuid[16]; + +    fw_cfg_read(FW_CFG_UUID, (char *)qemu_uuid, 16); + +    printk("UUID: " UUID_FMT "\n", qemu_uuid[0], qemu_uuid[1], qemu_uuid[2], +           qemu_uuid[3], qemu_uuid[4], qemu_uuid[5], qemu_uuid[6], +           qemu_uuid[7], qemu_uuid[8], qemu_uuid[9], qemu_uuid[10], +           qemu_uuid[11], qemu_uuid[12], qemu_uuid[13], qemu_uuid[14], +           qemu_uuid[15]); + +    push_str("/"); +    fword("find-device"); + +    PUSH((long)&qemu_uuid); +    PUSH(16); +    fword("encode-bytes"); +    push_str("uuid"); +    fword("property"); +} + +static void setup_stdio(void) +{ +    char nographic; +    const char *stdin, *stdout; + +    fw_cfg_read(FW_CFG_NOGRAPHIC, &nographic, 1); +    if (nographic) { +        obp_stdin = PROMDEV_TTYA; +        obp_stdout = PROMDEV_TTYA; +        stdin = "ttya"; +        stdout = "ttya"; +    } else { +        obp_stdin = PROMDEV_KBD; +        obp_stdout = PROMDEV_SCREEN; +        stdin = "keyboard"; +        stdout = "screen"; +    } + +    push_str(stdin); +    push_str("input-device"); +    fword("$setenv"); + +    push_str(stdout); +    push_str("output-device"); +    fword("$setenv"); + +    obp_stdin_path = stdin; +    obp_stdout_path = stdout; +} + +static void init_memory(void) +{ +    phys_addr_t phys; +    ucell virt; +     +    /* Claim the memory from OFMEM */ +    phys = ofmem_claim_phys(-1, MEMORY_SIZE, PAGE_SIZE); +    if (!phys) +        printk("panic: not enough physical memory on host system.\n"); +     +    virt = ofmem_claim_virt(OF_CODE_START - MEMORY_SIZE, MEMORY_SIZE, 0); +    if (!virt) +        printk("panic: not enough virtual memory on host system.\n"); + +    /* Generate the mapping (and lock translation into the TLBs) */ +    ofmem_map(phys, virt, MEMORY_SIZE, ofmem_arch_default_translation_mode(phys)); + +    /* we push start and end of memory to the stack +     * so that it can be used by the forth word QUIT +     * to initialize the memory allocator +     */ +     +    PUSH(virt); +    PUSH(virt + MEMORY_SIZE); +} + +static void +arch_init( void ) +{ +	char *cmdline; +        const char *kernel_cmdline; +        uint32_t temp; +        uint16_t machine_id; +        char buf[256]; +        unsigned long mem_size; + +        fw_cfg_init(); + +        fw_cfg_read(FW_CFG_SIGNATURE, buf, 4); +        buf[4] = '\0'; + +        printk("Configuration device id %s", buf); + +        temp = fw_cfg_read_i32(FW_CFG_ID); +        machine_id = fw_cfg_read_i16(FW_CFG_MACHINE_ID); + +        printk(" version %d machine id %d\n", temp, machine_id); + +        if (temp != 1) { +            printk("Incompatible configuration device version, freezing\n"); +            for(;;); +        } + +        graphic_depth = fw_cfg_read_i16(FW_CFG_SUN4M_DEPTH); + +	openbios_init(); +	modules_init(); +        ob_init_mmu(); +        ob_init_iommu(hwdef->iommu_base); +#ifdef CONFIG_DRIVER_OBIO +        mem_size = fw_cfg_read_i32(FW_CFG_RAM_SIZE); +	ob_obio_init(hwdef->slavio_base, hwdef->fd_offset, +                     hwdef->counter_offset, hwdef->intr_offset, hwdef->intr_ncpu, +                     hwdef->aux1_offset, hwdef->aux2_offset, +                     mem_size); + +        setup_machine(hwdef->slavio_base); + +        nvconf_init(); +#endif +#ifdef CONFIG_DRIVER_SBUS +#ifdef CONFIG_DEBUG_CONSOLE_VIDEO +	setup_video(); +#endif +	ob_sbus_init(hwdef->iommu_base + 0x1000ULL, qemu_machine_type); +#endif +	device_end(); + +        setup_cpu(hwdef->mid_offset); + +        setup_stdio(); +	/* Initialiase openprom romvec */ +        romvec = init_openprom(); + +	kernel_size = fw_cfg_read_i32(FW_CFG_KERNEL_SIZE); +	if (kernel_size) { +		kernel_image = fw_cfg_read_i32(FW_CFG_KERNEL_ADDR); + +		/* Mark the kernel memory as in use */ +		ofmem_claim_phys(PAGE_ALIGN(kernel_image), PAGE_ALIGN(kernel_size), 0); +		ofmem_claim_virt(PAGE_ALIGN(kernel_image), PAGE_ALIGN(kernel_size), 0); +	} + +        kernel_cmdline = (const char *) fw_cfg_read_i32(FW_CFG_KERNEL_CMDLINE); +        if (kernel_cmdline) { +            cmdline = strdup(kernel_cmdline); +            obp_arg.argv[1] = cmdline; +        } else { +	    cmdline = strdup(""); +	} +	qemu_cmdline = (uint32_t)cmdline; + +        /* Setup nvram variables */ +        push_str("/options"); +        fword("find-device"); +        push_str(cmdline); +        fword("encode-string"); +        push_str("boot-file"); +        fword("property"); + +	boot_device = fw_cfg_read_i16(FW_CFG_BOOT_DEVICE); + +	switch (boot_device) { +	case 'a': +		push_str("floppy"); +		break; +	case 'c': +		push_str("disk"); +		break; +	default: +	case 'd': +		push_str("cdrom:d cdrom"); +		break; +	case 'n': +		push_str("net"); +		break; +	} + +	fword("encode-string"); +	push_str("boot-device"); +	fword("property"); + +	device_end(); +	 +	bind_func("platform-boot", boot ); +	bind_func("(go)", go ); +	 +	/* Set up other properties */ +        push_str("/chosen"); +        fword("find-device"); + +        setup_uuid(); + +	/* Enable interrupts */ +	temp = get_psr(); +	temp = (temp & ~PSR_PIL) | (13 << 8); /* Enable CPU timer interrupt (level 14) */ +	put_psr(temp); +} + +extern struct _console_ops arch_console_ops; + +int openbios(void) +{ +        unsigned int i; + +        for (i = 0; i < sizeof(hwdefs) / sizeof(struct hwdef); i++) { +            if (hwdefs[i].machine_id_low <= qemu_machine_type && +                hwdefs[i].machine_id_high >= qemu_machine_type) { +                hwdef = &hwdefs[i]; +                break; +            } +        } +        if (!hwdef) +            for(;;); // Internal inconsistency, hang + +#ifdef CONFIG_DEBUG_CONSOLE +        init_console(arch_console_ops); +#endif +        /* Make sure we setup OFMEM before the MMU as we need malloc() to setup page tables */ +        ofmem_init(); + +#ifdef CONFIG_DRIVER_SBUS +        init_mmu_swift(); +#endif +#ifdef CONFIG_DEBUG_CONSOLE +#ifdef CONFIG_DEBUG_CONSOLE_SERIAL +	escc_uart_init(hwdef->serial_base | (CONFIG_SERIAL_PORT? 0ULL: 4ULL), +                  CONFIG_SERIAL_SPEED); +#endif +#ifdef CONFIG_DEBUG_CONSOLE_VIDEO +	kbd_init(hwdef->ms_kb_base); +#endif +#endif + +        collect_sys_info(&sys_info); + +        dict = (unsigned char *)sys_info.dict_start; +        dicthead = (cell)sys_info.dict_end; +        last = sys_info.dict_last; +        dictlimit = sys_info.dict_limit; + +	forth_init(); + +#ifdef CONFIG_DEBUG_BOOT +	printk("forth started.\n"); +	printk("initializing memory..."); +#endif + +	init_memory(); + +#ifdef CONFIG_DEBUG_BOOT +	printk("done\n"); +#endif + +	PUSH_xt( bind_noname_func(arch_init) ); +	fword("PREPOST-initializer"); + +	PC = (ucell)findword("initialize-of"); + +	if (!PC) { +		printk("panic: no dictionary entry point.\n"); +		return -1; +	} +#ifdef CONFIG_DEBUG_DICTIONARY +	printk("done (%d bytes).\n", dicthead); +	printk("Jumping to dictionary...\n"); +#endif + +	enterforth((xt_t)PC); + +        free(dict); +	return 0; +} diff --git a/roms/openbios/arch/sparc32/openbios.h b/roms/openbios/arch/sparc32/openbios.h new file mode 100644 index 00000000..f7d47eab --- /dev/null +++ b/roms/openbios/arch/sparc32/openbios.h @@ -0,0 +1,28 @@ +/* + *   Creation Date: <2004/01/15 16:14:05 samuel> + *   Time-stamp: <2004/01/15 16:14:05 samuel> + * + *	<openbios.h> + * + * + * + *   Copyright (C) 2004 Samuel Rydh (samuel@ibrium.se) + * + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License + *   version 2 + * + */ + +#ifndef _H_OPENBIOS +#define _H_OPENBIOS + +int openbios(void); + +/* console.c */ +extern unsigned char *vmem; +#ifdef CONFIG_DEBUG_CONSOLE +extern void     video_init(void); +#endif + +#endif   /* _H_OPENBIOS */ diff --git a/roms/openbios/arch/sparc32/openprom.h b/roms/openbios/arch/sparc32/openprom.h new file mode 100644 index 00000000..0676be84 --- /dev/null +++ b/roms/openbios/arch/sparc32/openprom.h @@ -0,0 +1,260 @@ +#ifndef __SPARC_OPENPROM_H +#define __SPARC_OPENPROM_H + +/* openprom.h:  Prom structures and defines for access to the OPENBOOT + *              prom routines and data areas. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +// #include <asm/vaddrs.h> + +/* Empirical constants... */ +#define	LINUX_OPPROM_MAGIC      0x10010407 + +#ifndef __ASSEMBLY__ +/* V0 prom device operations. */ +struct linux_dev_v0_funcs { +	int (*v0_devopen)(char *device_str); +	int (*v0_devclose)(int dev_desc); +	int (*v0_rdblkdev)(int dev_desc, int num_blks, int blk_st, char *buf); +	int (*v0_wrblkdev)(int dev_desc, int num_blks, int blk_st, char *buf); +	int (*v0_wrnetdev)(int dev_desc, int num_bytes, char *buf); +	int (*v0_rdnetdev)(int dev_desc, int num_bytes, char *buf); +	int (*v0_rdchardev)(int dev_desc, int num_bytes, int dummy, char *buf); +	int (*v0_wrchardev)(int dev_desc, int num_bytes, int dummy, char *buf); +	int (*v0_seekdev)(int dev_desc, long logical_offst, int from); +}; + +/* V2 and later prom device operations. */ +struct linux_dev_v2_funcs { +	int (*v2_inst2pkg)(int d);	/* Convert ihandle to phandle */ +	char * (*v2_dumb_mem_alloc)(char *va, unsigned sz); +	void (*v2_dumb_mem_free)(char *va, unsigned sz); + +	/* To map devices into virtual I/O space. */ +	char * (*v2_dumb_mmap)(char *virta, int which_io, unsigned paddr, unsigned sz); +	void (*v2_dumb_munmap)(char *virta, unsigned size); + +	int (*v2_dev_open)(char *devpath); +	void (*v2_dev_close)(int d); +	int (*v2_dev_read)(int d, char *buf, int nbytes); +	int (*v2_dev_write)(int d, char *buf, int nbytes); +	int (*v2_dev_seek)(int d, int hi, int lo); + +	/* Never issued (multistage load support) */ +	void (*v2_wheee2)(void); +	void (*v2_wheee3)(void); +}; + +struct linux_mlist_v0 { +	struct linux_mlist_v0 *theres_more; +	char *start_adr; +	unsigned num_bytes; +}; + +struct linux_mem_v0 { +	struct linux_mlist_v0 * const *v0_totphys; +	struct linux_mlist_v0 * const *v0_prommap; +	struct linux_mlist_v0 * const *v0_available; /* What we can use */ +}; + +/* Arguments sent to the kernel from the boot prompt. */ +struct linux_arguments_v0 { +	const char *argv[8]; +	char args[100]; +	char boot_dev[2]; +	int boot_dev_ctrl; +	int boot_dev_unit; +	int dev_partition; +	const char *kernel_file_name; +	void *aieee1;           /* XXX */ +}; + +/* V2 and up boot things. */ +struct linux_bootargs_v2 { +	const char **bootpath; +	const char **bootargs; +	const int *fd_stdin; +	const int *fd_stdout; +}; + +/* The top level PROM vector. */ +struct linux_romvec { +	/* Version numbers. */ +	unsigned int pv_magic_cookie; +	unsigned int pv_romvers; +	unsigned int pv_plugin_revision; +	unsigned int pv_printrev; + +	/* Version 0 memory descriptors. */ +	struct linux_mem_v0 pv_v0mem; + +	/* Node operations. */ +	const struct linux_nodeops *pv_nodeops; + +	char **pv_bootstr; +	struct linux_dev_v0_funcs pv_v0devops; + +	const char *pv_stdin; +	const char *pv_stdout; +#define	PROMDEV_KBD	0		/* input from keyboard */ +#define	PROMDEV_SCREEN	0		/* output to screen */ +#define	PROMDEV_TTYA	1		/* in/out to ttya */ +#define	PROMDEV_TTYB	2		/* in/out to ttyb */ + +	/* Blocking getchar/putchar.  NOT REENTRANT! (grr) */ +	int (*pv_getchar)(void); +	void (*pv_putchar)(int ch); + +	/* Non-blocking variants. */ +	int (*pv_nbgetchar)(void); +	int (*pv_nbputchar)(int ch); + +	void (*pv_putstr)(char *str, int len); + +	/* Miscellany. */ +	void (*pv_reboot)(char *bootstr); +	void (*pv_printf)(__const__ char *fmt, ...); +	void (*pv_abort)(void); +	__volatile__ unsigned int *pv_ticks; +	void (*pv_halt)(void); +	void (**pv_synchook)(void); + +	/* Evaluate a forth string, not different proto for V0 and V2->up. */ +	union { +		void (*v0_eval)(int len, char *str); +		void (*v2_eval)(char *str, int arg0, int arg1, int arg2, int arg3, int arg4); +	} pv_fortheval; + +	const struct linux_arguments_v0 * const *pv_v0bootargs; + +	/* Get ether address. */ +	unsigned int (*pv_enaddr)(int d, char *enaddr); + +	struct linux_bootargs_v2 pv_v2bootargs; +	struct linux_dev_v2_funcs pv_v2devops; + +	/* Prom version 3 memory allocation */ +	char * (*v3_memalloc)(char *va, unsigned int size, unsigned int align); + +	int filler[14]; + +	/* This one is sun4c/sun4 only. */ +	void (*pv_setctxt)(int ctxt, char *va, int pmeg); + +	/* Prom version 3 Multiprocessor routines. This stuff is crazy. +	 * No joke. Calling these when there is only one cpu probably +	 * crashes the machine, have to test this. :-) +	 */ + +	/* v3_cpustart() will start the cpu 'whichcpu' in mmu-context +	 * 'thiscontext' executing at address 'prog_counter' +	 */ +	int (*v3_cpustart)(unsigned int whichcpu, int ctxtbl_ptr, +			   int thiscontext, char *prog_counter); + +	/* v3_cpustop() will cause cpu 'whichcpu' to stop executing +	 * until a resume cpu call is made. +	 */ +	int (*v3_cpustop)(unsigned int whichcpu); + +	/* v3_cpuidle() will idle cpu 'whichcpu' until a stop or +	 * resume cpu call is made. +	 */ +	int (*v3_cpuidle)(unsigned int whichcpu); + +	/* v3_cpuresume() will resume processor 'whichcpu' executing +	 * starting with whatever 'pc' and 'npc' were left at the +	 * last 'idle' or 'stop' call. +	 */ +	int (*v3_cpuresume)(unsigned int whichcpu); +}; + +/* Routines for traversing the prom device tree. */ +struct linux_nodeops { +	int (*no_nextnode)(int node); +	int (*no_child)(int node); +        int (*no_proplen)(int node, const char *name); +        int (*no_getprop)(int node, const char *name, char *val); +        int (*no_setprop)(int node, const char *name, char *val, int len); +        const char * (*no_nextprop)(int node, const char *name); +}; + +/* More fun PROM structures for device probing. */ +#define PROMREG_MAX     16 +#define PROMVADDR_MAX   16 +#define PROMINTR_MAX    15 + +struct linux_prom_registers { +	unsigned int which_io;         /* is this in OBIO space? */ +	unsigned int phys_addr;        /* The physical address of this register */ +	unsigned int reg_size;         /* How many bytes does this register take up? */ +}; + +struct linux_prom_irqs { +	int pri;    /* IRQ priority */ +	int vector; /* This is foobar, what does it do? */ +}; + +/* Element of the "ranges" vector */ +struct linux_prom_ranges { +	unsigned int ot_child_space; +	unsigned int ot_child_base;		/* Bus feels this */ +	unsigned int ot_parent_space; +	unsigned int ot_parent_base;		/* CPU looks from here */ +	unsigned int or_size; +}; + +/* Ranges and reg properties are a bit different for PCI. */ +struct linux_prom_pci_registers { +	/* +	 * We don't know what information this field contain. +	 * We guess, PCI device function is in bits 15:8 +	 * So, ... +	 */ +	unsigned int which_io;  /* Let it be which_io */ + +	unsigned int phys_hi; +	unsigned int phys_lo; + +	unsigned int size_hi; +	unsigned int size_lo; +}; + +struct linux_prom_pci_ranges { +	unsigned int child_phys_hi;	/* Only certain bits are encoded here. */ +	unsigned int child_phys_mid; +	unsigned int child_phys_lo; + +	unsigned int parent_phys_hi; +	unsigned int parent_phys_lo; + +	unsigned int size_hi; +	unsigned int size_lo; +}; + +struct linux_prom_pci_assigned_addresses { +	unsigned int which_io; + +	unsigned int phys_hi; +	unsigned int phys_lo; + +	unsigned int size_hi; +	unsigned int size_lo; +}; + +struct linux_prom_ebus_ranges { +	unsigned int child_phys_hi; +	unsigned int child_phys_lo; + +	unsigned int parent_phys_hi; +	unsigned int parent_phys_mid; +	unsigned int parent_phys_lo; + +	unsigned int size; +}; + +#endif /* !(__ASSEMBLY__) */ + +#endif /* !(__SPARC_OPENPROM_H) */ diff --git a/roms/openbios/arch/sparc32/pgtsrmmu.h b/roms/openbios/arch/sparc32/pgtsrmmu.h new file mode 100644 index 00000000..64dbaa65 --- /dev/null +++ b/roms/openbios/arch/sparc32/pgtsrmmu.h @@ -0,0 +1,223 @@ +/* + * Taken from kernel for decoupling from <asm/page.h>. --zaitcev + * + * $Id: pgtsrmmu.h,v 1.2 1999/04/19 01:04:31 zaitcev Exp $ + * pgtsrmmu.h:  SRMMU page table defines and code. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef _PGTSRMMU_H +#define _PGTSRMMU_H + +/* PMD_SHIFT determines the size of the area a second-level page table can map */ +#define SRMMU_PMD_SHIFT         18 +#define SRMMU_PMD_SIZE          (1UL << SRMMU_PMD_SHIFT) +#define SRMMU_PMD_MASK          (~(SRMMU_PMD_SIZE-1)) +#define SRMMU_PMD_ALIGN(addr)   (((addr)+SRMMU_PMD_SIZE-1)&SRMMU_PMD_MASK) + +/* PGDIR_SHIFT determines what a third-level page table entry can map */ +#define SRMMU_PGDIR_SHIFT       24 +#define SRMMU_PGDIR_SIZE        (1UL << SRMMU_PGDIR_SHIFT) +#define SRMMU_PGDIR_MASK        (~(SRMMU_PGDIR_SIZE-1)) +#define SRMMU_PGDIR_ALIGN(addr) (((addr)+SRMMU_PGDIR_SIZE-1)&SRMMU_PGDIR_MASK) + +#define SRMMU_PTRS_PER_PTE      64 +#define SRMMU_PTRS_PER_PMD      64 +#define SRMMU_PTRS_PER_PGD      256 + +#define SRMMU_PTE_TABLE_SIZE    0x100 /* 64 entries, 4 bytes a piece */ +#define SRMMU_PMD_TABLE_SIZE    0x100 /* 64 entries, 4 bytes a piece */ +#define SRMMU_PGD_TABLE_SIZE    0x400 /* 256 entries, 4 bytes a piece */ + +#define SRMMU_VMALLOC_START   (0xfe300000) +#define SRMMU_VMALLOC_END     ~0x0UL + +/* Definition of the values in the ET field of PTD's and PTE's */ +#define SRMMU_ET_MASK         0x3 +#define SRMMU_ET_INVALID      0x0 +#define SRMMU_ET_PTD          0x1 +#define SRMMU_ET_PTE          0x2 +#define SRMMU_ET_REPTE        0x3 /* AIEEE, SuperSparc II reverse endian page! */ + +/* Physical page extraction from PTP's and PTE's. */ +#define SRMMU_CTX_PMASK    0xfffffff0 +#define SRMMU_PTD_PMASK    0xfffffff0 +#define SRMMU_PTE_PMASK    0xffffff00 + +/* The pte non-page bits.  Some notes: + * 1) cache, dirty, valid, and ref are frobbable + *    for both supervisor and user pages. + * 2) exec and write will only give the desired effect + *    on user pages + * 3) use priv and priv_readonly for changing the + *    characteristics of supervisor ptes + */ +#define SRMMU_CACHE        0x80 +#define SRMMU_DIRTY        0x40 +#define SRMMU_REF          0x20 +#define SRMMU_EXEC         0x08 +#define SRMMU_WRITE        0x04 +#define SRMMU_VALID        0x02 /* SRMMU_ET_PTE */ +#define SRMMU_PRIV         0x1c +#define SRMMU_PRIV_RDONLY  0x18 + +#define SRMMU_CHG_MASK    (0xffffff00 | SRMMU_REF | SRMMU_DIRTY) + +/* SRMMU Register addresses in ASI 0x4.  These are valid for all + * current SRMMU implementations that exist. + */ +#define SRMMU_CTRL_REG           0x00000000 +#define SRMMU_CTXTBL_PTR         0x00000100 +#define SRMMU_CTX_REG            0x00000200 +#define SRMMU_FAULT_STATUS       0x00000300 +#define SRMMU_FAULT_ADDR         0x00000400 + +#ifndef __ASSEMBLY__ + +/* Accessing the MMU control register. */ +static __inline__ unsigned int srmmu_get_mmureg(void) +{ +        unsigned int retval; +	__asm__ __volatile__("lda [%%g0] %1, %0\n\t" : +			     "=r" (retval) : +			     "i" (ASI_M_MMUREGS)); +	return retval; +} + +static __inline__ void srmmu_set_mmureg(unsigned long regval) +{ +	__asm__ __volatile__("sta %0, [%%g0] %1\n\t" : : +			     "r" (regval), "i" (ASI_M_MMUREGS) : "memory"); + +} + +static __inline__ void srmmu_set_ctable_ptr(unsigned long paddr) +{ +	paddr = ((paddr >> 4) & SRMMU_CTX_PMASK); +	__asm__ __volatile__("sta %0, [%1] %2\n\t" : : +			     "r" (paddr), "r" (SRMMU_CTXTBL_PTR), +			     "i" (ASI_M_MMUREGS) : +			     "memory"); +} + +static __inline__ unsigned long srmmu_get_ctable_ptr(void) +{ +	unsigned int retval; + +	__asm__ __volatile__("lda [%1] %2, %0\n\t" : +			     "=r" (retval) : +			     "r" (SRMMU_CTXTBL_PTR), +			     "i" (ASI_M_MMUREGS)); +	return (retval & SRMMU_CTX_PMASK) << 4; +} + +static __inline__ void srmmu_set_context(int context) +{ +	__asm__ __volatile__("sta %0, [%1] %2\n\t" : : +			     "r" (context), "r" (SRMMU_CTX_REG), +			     "i" (ASI_M_MMUREGS) : "memory"); +} + +static __inline__ int srmmu_get_context(void) +{ +	register int retval; +	__asm__ __volatile__("lda [%1] %2, %0\n\t" : +			     "=r" (retval) : +			     "r" (SRMMU_CTX_REG), +			     "i" (ASI_M_MMUREGS)); +	return retval; +} + +static __inline__ unsigned int srmmu_get_fstatus(void) +{ +	unsigned int retval; + +	__asm__ __volatile__("lda [%1] %2, %0\n\t" : +			     "=r" (retval) : +			     "r" (SRMMU_FAULT_STATUS), "i" (ASI_M_MMUREGS)); +	return retval; +} + +static __inline__ unsigned int srmmu_get_faddr(void) +{ +	unsigned int retval; + +	__asm__ __volatile__("lda [%1] %2, %0\n\t" : +			     "=r" (retval) : +			     "r" (SRMMU_FAULT_ADDR), "i" (ASI_M_MMUREGS)); +	return retval; +} + +/* This is guaranteed on all SRMMU's. */ +static __inline__ void srmmu_flush_whole_tlb(void) +{ +	__asm__ __volatile__("sta %%g0, [%0] %1\n\t": : +			     "r" (0x400),        /* Flush entire TLB!! */ +			     "i" (ASI_M_FLUSH_PROBE) : "memory"); + +} + +/* These flush types are not available on all chips... */ +static __inline__ void srmmu_flush_tlb_ctx(void) +{ +	__asm__ __volatile__("sta %%g0, [%0] %1\n\t": : +			     "r" (0x300),        /* Flush TLB ctx.. */ +			     "i" (ASI_M_FLUSH_PROBE) : "memory"); + +} + +static __inline__ void srmmu_flush_tlb_region(unsigned long addr) +{ +	addr &= SRMMU_PGDIR_MASK; +	__asm__ __volatile__("sta %%g0, [%0] %1\n\t": : +			     "r" (addr | 0x200), /* Flush TLB region.. */ +			     "i" (ASI_M_FLUSH_PROBE) : "memory"); + +} + + +static __inline__ void srmmu_flush_tlb_segment(unsigned long addr) +{ +	addr &= SRMMU_PMD_MASK; +	__asm__ __volatile__("sta %%g0, [%0] %1\n\t": : +			     "r" (addr | 0x100), /* Flush TLB segment.. */ +			     "i" (ASI_M_FLUSH_PROBE) : "memory"); + +} + +static __inline__ void srmmu_flush_tlb_page(unsigned long page) +{ +	page &= PAGE_MASK; +	__asm__ __volatile__("sta %%g0, [%0] %1\n\t": : +			     "r" (page),        /* Flush TLB page.. */ +			     "i" (ASI_M_FLUSH_PROBE) : "memory"); + +} + +static __inline__ unsigned long srmmu_hwprobe(unsigned long vaddr) +{ +	unsigned long retval; + +	vaddr &= PAGE_MASK; +	__asm__ __volatile__("lda [%1] %2, %0\n\t" : +			     "=r" (retval) : +			     "r" (vaddr | 0x400), "i" (ASI_M_FLUSH_PROBE)); + +	return retval; +} + +static __inline__ int +srmmu_get_pte (unsigned long addr) +{ +	register unsigned long entry; + +	__asm__ __volatile__("\n\tlda [%1] %2,%0\n\t" : +				"=r" (entry): +				"r" ((addr & 0xfffff000) | 0x400), "i" (ASI_M_FLUSH_PROBE)); +	return entry; +} + +#endif /* !(__ASSEMBLY__) */ + +#endif /* !(_SPARC_PGTSRMMU_H) */ diff --git a/roms/openbios/arch/sparc32/plainboot.c b/roms/openbios/arch/sparc32/plainboot.c new file mode 100644 index 00000000..08dab2d1 --- /dev/null +++ b/roms/openbios/arch/sparc32/plainboot.c @@ -0,0 +1,21 @@ +/* tag: openbios fixed address forth starter + * + * Copyright (C) 2003 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#include "config.h" +#include "libopenbios/sys_info.h" +#include "multiboot.h" + +#define FIXED_DICTSTART 0xfffe0000 +#define FIXED_DICTEND   0xfffeffff + +void collect_multiboot_info(struct sys_info *info); +void collect_multiboot_info(struct sys_info *info) +{ +	info->dict_start=(unsigned long *)FIXED_DICTSTART; +	info->dict_end=(unsigned long *)FIXED_DICTEND; +} diff --git a/roms/openbios/arch/sparc32/psr.h b/roms/openbios/arch/sparc32/psr.h new file mode 100644 index 00000000..0f6cfabb --- /dev/null +++ b/roms/openbios/arch/sparc32/psr.h @@ -0,0 +1,88 @@ +/* $Id: psr.h,v 1.1 2002/07/12 17:12:03 zaitcev Exp $ + * psr.h: This file holds the macros for masking off various parts of + *        the processor status register on the Sparc. This is valid + *        for Version 8. On the V9 this is renamed to the PSTATE + *        register and its members are accessed as fields like + *        PSTATE.PRIV for the current CPU privilege level. + * + * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef __LINUX_SPARC_PSR_H +#define __LINUX_SPARC_PSR_H + +/* The Sparc PSR fields are laid out as the following: + * + *  ------------------------------------------------------------------------ + *  | impl  | vers  | icc   | resv  | EC | EF | PIL  | S | PS | ET |  CWP  | + *  | 31-28 | 27-24 | 23-20 | 19-14 | 13 | 12 | 11-8 | 7 | 6  | 5  |  4-0  | + *  ------------------------------------------------------------------------ + */ +#define PSR_CWP     0x0000001f         /* current window pointer     */ +#define PSR_ET      0x00000020         /* enable traps field         */ +#define PSR_PS      0x00000040         /* previous privilege level   */ +#define PSR_S       0x00000080         /* current privilege level    */ +#define PSR_PIL     0x00000f00         /* processor interrupt level  */ +#define PSR_EF      0x00001000         /* enable floating point      */ +#define PSR_EC      0x00002000         /* enable co-processor        */ +#define PSR_LE      0x00008000         /* SuperSparcII little-endian */ +#define PSR_ICC     0x00f00000         /* integer condition codes    */ +#define PSR_C       0x00100000         /* carry bit                  */ +#define PSR_V       0x00200000         /* overflow bit               */ +#define PSR_Z       0x00400000         /* zero bit                   */ +#define PSR_N       0x00800000         /* negative bit               */ +#define PSR_VERS    0x0f000000         /* cpu-version field          */ +#define PSR_IMPL    0xf0000000         /* cpu-implementation field   */ + +#ifndef __ASSEMBLY +/* Get the %psr register. */ +static __inline__ unsigned int get_psr(void) +{ +	unsigned int psr; +	__asm__ __volatile__( +		"rd	%%psr, %0\n\t" +		"nop\n\t" +		"nop\n\t" +		"nop\n\t" +	: "=r" (psr) +	: /* no inputs */ +	: "memory"); + +	return psr; +} + +static __inline__ void put_psr(unsigned int new_psr) +{ +	__asm__ __volatile__( +		"wr	%0, 0x0, %%psr\n\t" +		"nop\n\t" +		"nop\n\t" +		"nop\n\t" +	: /* no outputs */ +	: "r" (new_psr) +	: "memory", "cc"); +} + +/* Get the %fsr register.  Be careful, make sure the floating point + * enable bit is set in the %psr when you execute this or you will + * incur a trap. + */ + +static unsigned int fsr_storage; + +static __inline__ unsigned int get_fsr(void) +{ +	unsigned int fsr = 0; + +	__asm__ __volatile__( +		"st	%%fsr, %1\n\t" +		"ld	%1, %0\n\t" +	: "=r" (fsr) +	: "m" (fsr_storage)); + +	return fsr; +} + +#endif /* !(__ASSEMBLY__) */ + +#endif /* !(__LINUX_SPARC_PSR_H) */ diff --git a/roms/openbios/arch/sparc32/romvec.c b/roms/openbios/arch/sparc32/romvec.c new file mode 100644 index 00000000..8757c28f --- /dev/null +++ b/roms/openbios/arch/sparc32/romvec.c @@ -0,0 +1,524 @@ +/* + * PROM interface support + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * Copyright 1999 Pete A. Zaitcev + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ + +#include <stdarg.h> + +#include "openprom.h" +#include "config.h" +#include "libopenbios/bindings.h" +#include "drivers/drivers.h" +#include "libopenbios/sys_info.h" +#include "boot.h" +#include "romvec.h" + +#ifdef CONFIG_DEBUG_OBP +#define DPRINTF(fmt, args...)                   \ +    do { printk(fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) +#endif + +char obp_stdin, obp_stdout; +const char *obp_stdin_path, *obp_stdout_path; + +struct linux_arguments_v0 obp_arg; +const char *bootpath; +static const struct linux_arguments_v0 * const obp_argp = &obp_arg; + +static void (*sync_hook)(void); + +static struct linux_romvec romvec0; + +static void doublewalk(__attribute__((unused)) unsigned int ptab1, +                       __attribute__((unused)) unsigned int va) +{ +} + +int obp_nextnode(int node) +{ +    int peer; + +    PUSH(node); +    fword("peer"); +    peer = POP(); +    DPRINTF("obp_nextnode(0x%x) = 0x%x\n", node, peer); + +    return peer; +} + +int obp_child(int node) +{ +    int child; + +    PUSH(node); +    fword("child"); +    child = POP(); +    DPRINTF("obp_child(0x%x) = 0x%x\n", node, child); + +    return child; +} + +int obp_proplen(int node, const char *name) +{ +    int notfound; + +    if (!node) { +        DPRINTF("obp_proplen(0x0, %s) = -1\n", name); +        return -1; +    } + +    push_str(name); +    PUSH(node); +    fword("get-package-property"); +    notfound = POP(); + +    if (notfound) { +        DPRINTF("obp_proplen(0x%x, %s) (not found)\n", node, name); + +        return -1; +    } else { +        int len; + +        len = POP(); +        (void) POP(); +        DPRINTF("obp_proplen(0x%x, %s) = %d\n", node, name, len); + +        return len; +    } +} + +#ifdef CONFIG_DEBUG_OBP +static int looks_like_string(const char *str, int len) +{ +    int i; +    int ret = (str[len-1] == '\0'); +    for (i = 0; i < len-1 && ret; i++) +    { +        int ch = str[i] & 0xFF; +        if (ch < 0x20 || ch > 0x7F) +            ret = 0; +    } +    return ret; +} +#endif + +int obp_getprop(int node, const char *name, char *value) +{ +    int notfound, found; +    int len; +    const char *str; + +    if (!node) { +        DPRINTF("obp_getprop(0x0, %s) = -1\n", name); +        return -1; +    } + +    if (!name) { +        // NULL name means get first property +        push_str(""); +        PUSH(node); +        fword("next-property"); +        found = POP(); +        if (found) { +            len = POP(); +            str = (char *) POP(); +            DPRINTF("obp_getprop(0x%x, NULL) = %s\n", node, str); + +            return (int)str; +        } +        DPRINTF("obp_getprop(0x%x, NULL) (not found)\n", node); + +        return -1; +    } else { +        push_str(name); +        PUSH(node); +        fword("get-package-property"); +        notfound = POP(); +    } +    if (notfound) { +        DPRINTF("obp_getprop(0x%x, %s) (not found)\n", node, name); + +        return -1; +    } else { +        len = POP(); +        str = (char *) POP(); +        if (len > 0) +            memcpy(value, str, len); +        else +            str = "NULL"; + +#ifdef CONFIG_DEBUG_OBP +        if (looks_like_string(str, len)) { +            DPRINTF("obp_getprop(0x%x, %s) = %s\n", node, name, str); +        } else { +            int i; +            DPRINTF("obp_getprop(0x%x, %s) = ", node, name); +            for (i = 0; i < len; i++) { +                DPRINTF("%02x%s", str[i] & 0xFF, +                        (len == 4 || i == len-1) ? "" : " "); +            } +            DPRINTF("\n"); +        } +#endif + +        return len; +    } +} + +const char *obp_nextprop(int node, const char *name) +{ +    int found; + +    if (!name || *name == '\0') { +        // NULL name means get first property +        push_str(""); +        name = "NULL"; +    } else { +        push_str(name); +    } +    PUSH(node); +    fword("next-property"); +    found = POP(); +    if (!found) { +        DPRINTF("obp_nextprop(0x%x, %s) (not found)\n", node, name); + +        return ""; +    } else { +        char *str; + +        POP(); /* len */ +        str = (char *) POP(); + +        DPRINTF("obp_nextprop(0x%x, %s) = %s\n", node, name, str); + +        return str; +    } +} + +int obp_setprop(__attribute__((unused)) int node, +                       __attribute__((unused)) const char *name, +		       __attribute__((unused)) char *value, +		       __attribute__((unused)) int len) +{ +    DPRINTF("obp_setprop(0x%x, %s) = %s (%d)\n", node, name, value, len); + +    return -1; +} + +static const struct linux_nodeops nodeops0 = { +    obp_nextnode_handler,	/* int (*no_nextnode)(int node); */ +    obp_child_handler,	        /* int (*no_child)(int node); */ +    obp_proplen_handler,	/* int (*no_proplen)(int node, char *name); */ +    obp_getprop_handler,	/* int (*no_getprop)(int node,char *name,char *val); */ +    obp_setprop_handler,	/* int (*no_setprop)(int node, char *name, +                   	        char *val, int len); */ +    obp_nextprop_handler	/* char * (*no_nextprop)(int node, char *name); */ +}; + +int obp_nbgetchar(void) +{ +    return getchar(); +} + +int obp_nbputchar(int ch) +{ +    putchar(ch); + +    return 0; +} + +void obp_putstr(char *str, int len) +{ +    PUSH(pointer2cell(str)); +    PUSH(len); +    fword("type"); +} + +void obp_printf(const char *fmt, ...) +{ +    va_list ap; + +    va_start(ap, fmt); +    printk(fmt, ap); +    va_end(ap); +} + +void obp_reboot(char *str) +{ +    printk("rebooting (%s)\n", str); +    *reset_reg = 1; +    printk("reboot failed\n"); +    for (;;) {} +} + +void obp_abort(void) +{ +    printk("abort, power off\n"); +    *power_reg = 1; +    printk("power off failed\n"); +    for (;;) {} +} + +void obp_halt(void) +{ +    printk("halt, power off\n"); +    *power_reg = 1; +    printk("power off failed\n"); +    for (;;) {} +} + +int obp_devopen(char *str) +{ +    int ret; + +    push_str(str); +    fword("open-dev"); +    ret = POP(); +    DPRINTF("obp_devopen(%s) = 0x%x\n", str, ret); + +    return ret; +} + +int obp_devclose(int dev_desc) +{ +    int ret = 1; + +    PUSH(dev_desc); +    fword("close-dev"); + +    DPRINTF("obp_devclose(0x%x) = %d\n", dev_desc, ret); + +    return ret; +} + +int obp_rdblkdev(int dev_desc, int num_blks, int offset, char *buf) +{ +    int ret, hi, lo, bs; + +    bs = 512; +    hi = ((uint64_t)offset * bs) >> 32; +    lo = ((uint64_t)offset * bs) & 0xffffffff; + +    ret = obp_devseek(dev_desc, hi, lo); + +    ret = obp_devread(dev_desc, buf, num_blks * bs) / bs; + +    DPRINTF("obp_rdblkdev(fd 0x%x, num_blks %d, offset %d (hi %d lo %d), buf 0x%x) = %d\n", dev_desc, num_blks, offset, hi, lo, (int)buf, ret); + +    return ret; +} + +int obp_devread(int dev_desc, char *buf, int nbytes) +{ +    int ret; + +    PUSH((int)buf); +    PUSH(nbytes); +    push_str("read"); +    PUSH(dev_desc); +    fword("$call-method"); +    ret = POP(); + +    DPRINTF("obp_devread(fd 0x%x, buf 0x%x, nbytes %d) = %d\n", dev_desc, (int)buf, nbytes, ret); + +    return ret; +} + +int obp_devwrite(int dev_desc, char *buf, int nbytes) +{ +#ifdef CONFIG_DEBUG_OBP_DEVWRITE /* disabled, makes too much noise */ +    int ret; +#endif + +    PUSH((int)buf); +    PUSH(nbytes); +    push_str("write"); +    PUSH(dev_desc); +    fword("$call-method"); +#ifdef CONFIG_DEBUG_OBP_DEVWRITE +    ret = POP(); +    DPRINTF("obp_devwrite(fd 0x%x, buf %s, nbytes %d) = %d\n", dev_desc, buf, nbytes, ret); +#else +    POP(); +#endif + +    return nbytes; +} + +int obp_devseek(int dev_desc, int hi, int lo) +{ +    int ret; + +    PUSH(lo); +    PUSH(hi); +    push_str("seek"); +    PUSH(dev_desc); +    fword("$call-method"); +    ret = POP(); + +    DPRINTF("obp_devseek(fd 0x%x, hi %d, lo %d) = %d\n", dev_desc, hi, lo, ret); + +    return ret; +} + +int obp_inst2pkg(int dev_desc) +{ +    int ret; + +    PUSH(dev_desc); +    fword("ihandle>non-interposed-phandle"); +    ret = POP(); + +    DPRINTF("obp_inst2pkg(fd 0x%x) = 0x%x\n", dev_desc, ret); + +    return ret; +} + +int obp_cpustart(__attribute__((unused))unsigned int whichcpu, +                        __attribute__((unused))int ctxtbl_ptr, +                        __attribute__((unused))int thiscontext, +                        __attribute__((unused))char *prog_counter) +{ +    int cpu, found; +    struct linux_prom_registers *smp_ctable = (void *)ctxtbl_ptr; + +    DPRINTF("obp_cpustart: cpu %d, ctxptr 0x%x, ctx %d, pc 0x%x\n", whichcpu, +            smp_ctable->phys_addr, thiscontext, (unsigned int)prog_counter); + +    found = obp_getprop(whichcpu, "mid", (char *)&cpu); +    if (found == -1) +        return -1; +    DPRINTF("cpu found, id %d -> cpu %d\n", whichcpu, cpu); + +    return start_cpu((unsigned int)prog_counter, ((unsigned int)smp_ctable->phys_addr) >> 4, +              thiscontext, cpu); +} + +int obp_cpustop(__attribute__((unused)) unsigned int whichcpu) +{ +    DPRINTF("obp_cpustop: cpu %d\n", whichcpu); + +    return 0; +} + +int obp_cpuidle(__attribute__((unused)) unsigned int whichcpu) +{ +    DPRINTF("obp_cpuidle: cpu %d\n", whichcpu); + +    return 0; +} + +int obp_cpuresume(__attribute__((unused)) unsigned int whichcpu) +{ +    DPRINTF("obp_cpuresume: cpu %d\n", whichcpu); + +    return 0; +} + +void obp_fortheval_v2(char *str, int arg0, int arg1, int arg2, int arg3, int arg4) +{ +  int dstacktmp = 0; + +  // It seems Solaris passes up to 5 arguments which should be pushed onto the Forth +  // stack for execution. However the API doesn't provide for a way to specify the number +  // of arguments actually being passed. Hence we preserve the state of the Forth stack  +  // before, push all the arguments, execute the Forth, then restore the stack to its  +  // previous state. This enables us to have a variable number of arguments and still  +  // preserve stack state between subsequent calls. + +  // Preserve stack state +  dstacktmp = dstackcnt; + +  PUSH(arg4); +  PUSH(arg3); +  PUSH(arg2); +  PUSH(arg1); +  PUSH(arg0); + +  DPRINTF("obp_fortheval_v2(%x %x %x %x %x %s)\n", arg4, arg3, arg2, arg1, arg0, str); +  push_str(str); +  fword("eval"); + +  // Restore stack state +  dstackcnt = dstacktmp; +} + +volatile uint32_t *obp_ticks; + +void * +init_openprom(void) +{ +    /* Setup the openprom vector. Note that all functions should be invoked +       via their handler (see call-romvec.S) which acts as a proxy to save +       the globals and setup the stack correctly */ + +    // Linux wants a R/W romvec table +    romvec0.pv_magic_cookie = LINUX_OPPROM_MAGIC; +    romvec0.pv_romvers = 3; +    romvec0.pv_plugin_revision = 2; +    romvec0.pv_printrev = 0x20019; +    romvec0.pv_v0mem.v0_totphys = NULL; +    romvec0.pv_v0mem.v0_prommap = NULL; +    romvec0.pv_v0mem.v0_available = NULL; +    romvec0.pv_nodeops = &nodeops0; +    romvec0.pv_bootstr = (void *)doublewalk; +    romvec0.pv_v0devops.v0_devopen = &obp_devopen_handler; +    romvec0.pv_v0devops.v0_devclose = &obp_devclose_handler; +    romvec0.pv_v0devops.v0_rdblkdev = &obp_rdblkdev_handler; +    romvec0.pv_stdin = &obp_stdin; +    romvec0.pv_stdout = &obp_stdout; +    romvec0.pv_getchar = obp_nbgetchar_handler; +    romvec0.pv_putchar = (void (*)(int))obp_nbputchar_handler; +    romvec0.pv_nbgetchar = obp_nbgetchar_handler; +    romvec0.pv_nbputchar = obp_nbputchar_handler; +    romvec0.pv_putstr = obp_putstr_handler; +    romvec0.pv_reboot = obp_reboot_handler; +    romvec0.pv_printf = obp_printf_handler; +    romvec0.pv_abort = obp_abort_handler; +     +    /* Point to the Forth obp-ticks variable and reset */ +    fword("obp-ticks"); +    obp_ticks = cell2pointer(POP()); +    *obp_ticks = 0; +    romvec0.pv_ticks = obp_ticks; +     +    romvec0.pv_halt = obp_halt_handler; +    romvec0.pv_synchook = &sync_hook; +    romvec0.pv_v0bootargs = &obp_argp; +    romvec0.pv_fortheval.v2_eval = obp_fortheval_v2_handler; +    romvec0.pv_v2devops.v2_inst2pkg = obp_inst2pkg_handler; +    romvec0.pv_v2devops.v2_dumb_mem_alloc = obp_dumb_memalloc_handler; +    romvec0.pv_v2devops.v2_dumb_mem_free = obp_dumb_memfree_handler; +    romvec0.pv_v2devops.v2_dumb_mmap = obp_dumb_mmap_handler; +    romvec0.pv_v2devops.v2_dumb_munmap = obp_dumb_munmap_handler; +    romvec0.pv_v2devops.v2_dev_open = obp_devopen_handler; +    romvec0.pv_v2devops.v2_dev_close = (void (*)(int))obp_devclose_handler; +    romvec0.pv_v2devops.v2_dev_read = obp_devread_handler; +    romvec0.pv_v2devops.v2_dev_write = obp_devwrite_handler; +    romvec0.pv_v2devops.v2_dev_seek = obp_devseek_handler; + +    romvec0.pv_v2bootargs.bootpath = &bootpath; + +    romvec0.pv_v2bootargs.bootargs = &obp_arg.argv[1]; + +    /* Point fd_stdin/fd_stdout to the Forth stdin/stdout variables */ +    fword("stdin"); +    romvec0.pv_v2bootargs.fd_stdin = cell2pointer(POP()); +    fword("stdout"); +    romvec0.pv_v2bootargs.fd_stdout = cell2pointer(POP()); + +    romvec0.v3_memalloc = obp_memalloc_handler; + +    romvec0.v3_cpustart = obp_cpustart_handler; +    romvec0.v3_cpustop = obp_cpustop_handler; +    romvec0.v3_cpuidle = obp_cpuidle_handler; +    romvec0.v3_cpuresume = obp_cpuresume_handler; + +    return &romvec0; +} diff --git a/roms/openbios/arch/sparc32/romvec.h b/roms/openbios/arch/sparc32/romvec.h new file mode 100644 index 00000000..4375f06f --- /dev/null +++ b/roms/openbios/arch/sparc32/romvec.h @@ -0,0 +1,79 @@ +/* + * romvec main C function and handler declarations + */ + +extern volatile uint32_t *obp_ticks; +void *init_openprom(void); + +int obp_devopen(char *str); +int obp_devopen_handler(char *str); +int obp_devclose(int dev_desc); +int obp_devclose_handler(int dev_desc); +int obp_rdblkdev(int dev_desc, int num_blks, int offset, char *buf); +int obp_rdblkdev_handler(int dev_desc, int num_blks, int offset, char *buf); +int obp_nbgetchar(void); +int obp_nbgetchar_handler(void); +int obp_nbputchar(int ch); +int obp_nbputchar_handler(int ch); +void obp_putstr(char *str, int len); +void obp_putstr_handler(char *str, int len); +void obp_printf(__const__ char *fmt, ...); +void obp_printf_handler(__const__ char *fmt, ...); +void obp_reboot(char *str); +void obp_reboot_handler(char *str); +void obp_abort(void); +void obp_abort_handler(void); +void obp_halt(void); +void obp_halt_handler(void); +void obp_fortheval_v2(char *str, int arg0, int arg1, int arg2, int arg3, int arg4); +void obp_fortheval_v2_handler(char *str, int arg0, int arg1, int arg2, int arg3, int arg4); +int obp_inst2pkg(int dev_desc); +int obp_inst2pkg_handler(int dev_desc); +char *obp_dumb_memalloc(char *va, unsigned int size); +char *obp_dumb_memalloc_handler(char *va, unsigned int size); +void obp_dumb_memfree(char *va, unsigned size); +void obp_dumb_memfree_handler(char *va, unsigned size); +char *obp_dumb_mmap(char *va, int which_io, unsigned int pa, unsigned int size); +char *obp_dumb_mmap_handler(char *va, int which_io, unsigned int pa, unsigned int size); +void obp_dumb_munmap(__attribute__((unused)) char *va, __attribute__((unused)) unsigned int size); +void obp_dumb_munmap_handler(__attribute__((unused)) char *va, __attribute__((unused)) unsigned int size); +int obp_devread(int dev_desc, char *buf, int nbytes); +int obp_devread_handler(int dev_desc, char *buf, int nbytes); +int obp_devwrite(int dev_desc, char *buf, int nbytes); +int obp_devwrite_handler(int dev_desc, char *buf, int nbytes); +int obp_devseek(int dev_desc, int hi, int lo); +int obp_devseek_handler(int dev_desc, int hi, int lo); +int obp_cpustart(__attribute__((unused))unsigned int whichcpu, +                        __attribute__((unused))int ctxtbl_ptr, +                        __attribute__((unused))int thiscontext, +                        __attribute__((unused))char *prog_counter); +int obp_cpustart_handler(__attribute__((unused))unsigned int whichcpu, +                        __attribute__((unused))int ctxtbl_ptr, +                        __attribute__((unused))int thiscontext, +                        __attribute__((unused))char *prog_counter); +int obp_cpustop(__attribute__((unused)) unsigned int whichcpu); +int obp_cpustop_handler(__attribute__((unused)) unsigned int whichcpu); +int obp_cpuidle(__attribute__((unused)) unsigned int whichcpu); +int obp_cpuidle_handler(__attribute__((unused)) unsigned int whichcpu); +int obp_cpuresume(__attribute__((unused)) unsigned int whichcpu); +int obp_cpuresume_handler(__attribute__((unused)) unsigned int whichcpu); +int obp_nextnode(int node); +int obp_nextnode_handler(int node); +int obp_child(int node); +int obp_child_handler(int node); +int obp_proplen(int node, const char *name); +int obp_proplen_handler(int node, const char *name); +int obp_getprop(int node, const char *name, char *value); +int obp_getprop_handler(int node, const char *name, char *value); +int obp_setprop(__attribute__((unused)) int node, +                       __attribute__((unused)) const char *name, +		       __attribute__((unused)) char *value, +		       __attribute__((unused)) int len); +int obp_setprop_handler(__attribute__((unused)) int node, +                       __attribute__((unused)) const char *name, +		       __attribute__((unused)) char *value, +		       __attribute__((unused)) int len); +const char *obp_nextprop(int node, const char *name); +const char *obp_nextprop_handler(int node, const char *name); +char *obp_memalloc(char *va, unsigned int size, unsigned int align); +char *obp_memalloc_handler(char *va, unsigned int size, unsigned int align); diff --git a/roms/openbios/arch/sparc32/switch.S b/roms/openbios/arch/sparc32/switch.S new file mode 100644 index 00000000..d5b1b659 --- /dev/null +++ b/roms/openbios/arch/sparc32/switch.S @@ -0,0 +1,154 @@ +#define __ASSEMBLY +#include "psr.h" +#include "asm/asi.h" +#define ASI_BP ASI_M_BYPASS +#define REGWIN_SZ   0x40 + +	.globl	__switch_context, __switch_context_nosave, __exit_context, halt + +	.text +	.align	4 + +#define STACKFRAME_SZ     0x60 + +/* These are just handy. */ +#define _SV	save	%sp, -STACKFRAME_SZ, %sp +#define _RS     restore + +#define FLUSH_ALL_KERNEL_WINDOWS \ +	_SV; _SV; _SV; _SV; _SV; _SV; _SV; \ +	_RS; _RS; _RS; _RS; _RS; _RS; _RS; + +/* + * Switch execution context + * This saves registers in the stack, then + * switches the stack, and restores everything from the new stack. + * This function takes no argument. New stack pointer is + * taken from global variable __context, and old stack pointer + * is also saved to __context. This way we can just jump to + * this routine to get back to the original context. + */ + +__switch_context: +        FLUSH_ALL_KERNEL_WINDOWS +	/* Save everything in stack */ +        st      %fp, [%fp + 120 -144] +        add     %fp, -144, %fp +        st      %g1, [%fp + 4] +        st      %g2, [%fp + 8] +        st      %g3, [%fp + 12] +        st      %g4, [%fp + 16] +        st      %g5, [%fp + 20] +        st      %g6, [%fp + 24] +        st      %g7, [%fp + 28] + +        st      %o0, [%fp + 32] +        st      %o1, [%fp + 36] +        st      %o2, [%fp + 40] +        st      %o3, [%fp + 44] +        st      %o4, [%fp + 48] +        st      %o5, [%fp + 52] +        st      %sp, [%fp + 56] +        st      %o7, [%fp + 60] + +        st      %l0, [%fp + 64] +        st      %l1, [%fp + 68] +        st      %l2, [%fp + 72] +        st      %l3, [%fp + 76] +        st      %l4, [%fp + 80] +        st      %l5, [%fp + 84] +        st      %l6, [%fp + 88] +        st      %l7, [%fp + 92] + +        st      %i0, [%fp + 96] +        st      %i1, [%fp + 100] +        st      %i2, [%fp + 104] +        st      %i3, [%fp + 108] +        st      %i4, [%fp + 112] +        st      %i5, [%fp + 116] +        st      %i7, [%fp + 124] + +        /* ctx->return_address:  Return to caller */ +        st      %o7, [%fp + 128] + +	/* Interrupts are not allowed... */ + +	/* Turn on Supervisor, EnableFloating, and all the PIL bits. +	 * Also puts us in register window zero with traps off. +	 */ +#if 0 +	set	(PSR_PS | PSR_S | PSR_PIL | PSR_EF), %g2 +	wr	%g2, 0x0, %psr +#endif +        set     __context, %g1 +        /* Swap ctx pointer with %fp and jump*/ +        ba     __set_context +         swap      [%g1], %fp +__switch_context_nosave: +        set     __context, %g1 +        /* load %fp from ctx pointer */ +        ld      [%g1], %fp +__set_context: +	/* Load all registers */ +        /* offset 0: %g0, no need to load */ +        ld      [%fp + 4], %g1 +        ld      [%fp + 8], %g2 +        ld      [%fp + 12], %g3 +        ld      [%fp + 16], %g4 +        ld      [%fp + 20], %g5 +        ld      [%fp + 24], %g6 +        ld      [%fp + 28], %g7 + +        /* offset 32: %o0, loaded from ctx->param */ +        ld      [%fp + 36], %o1 +        ld      [%fp + 40], %o2 +        ld      [%fp + 44], %o3 +        ld      [%fp + 48], %o4 +        ld      [%fp + 52], %o5 +        ld      [%fp + 56], %sp +        /* offset 60: %o7, loaded from ctx->return_addr */ + +        ld      [%fp + 64], %l0 +        ld      [%fp + 68], %l1 +        ld      [%fp + 72], %l2 +        ld      [%fp + 76], %l3 +        ld      [%fp + 80], %l4 +        ld      [%fp + 84], %l5 +        ld      [%fp + 88], %l6 +        ld      [%fp + 92], %l7 + +        ld      [%fp + 96], %i0 +        ld      [%fp + 100], %i1 +        ld      [%fp + 104], %i2 +        ld      [%fp + 108], %i3 +        ld      [%fp + 112], %i4 +        ld      [%fp + 116], %i5 +        ld      [%fp + 124], %i7 + +        /* ctx->return_addr */ +        ld      [%fp + 136], %o7 + +        /* ctx->param */ +        ld      [%fp + 140], %o0 + +        /* ctx->pc, save %g1 to %y and load to %g1 */ +        mov     %g1, %y +        ld      [%fp + 128], %g1 +        /* %fp last */ +        ld      [%fp + 120], %fp +        /* Finally, get the new %pc from %g1 and restore %g1*/ +        jmp     %g1 +         mov    %y, %g1 + +        FLUSH_ALL_KERNEL_WINDOWS +__exit_context: +	/* Get back to the original context */ +	call	__switch_context +	 nop + +	/* We get here if the other context attempt to switch to this +	 * dead context. This should not happen. */ + +halt: +	b	halt +	 nop diff --git a/roms/openbios/arch/sparc32/sys_info.c b/roms/openbios/arch/sparc32/sys_info.c new file mode 100644 index 00000000..719537d4 --- /dev/null +++ b/roms/openbios/arch/sparc32/sys_info.c @@ -0,0 +1,58 @@ +#include "config.h" +#include "kernel/kernel.h" +#include "arch/common/elf_boot.h" +#include "libopenbios/sys_info.h" +#include "context.h" +#include "boot.h" + +#define printf printk +#ifdef CONFIG_DEBUG_BOOT +#define debug printk +#else +#define debug(x...) +#endif + +unsigned int qemu_mem_size; + +void collect_multiboot_info(struct sys_info *); + +void collect_sys_info(struct sys_info *info) +{ +    int i; +    unsigned long long total = 0; +    struct memrange *mmap; + +    /* Pick up paramters given by bootloader to us */ +    //info->boot_type = boot_ctx->eax; +    //info->boot_data = boot_ctx->ebx; +    info->boot_arg = boot_ctx->param[0]; +    //debug("boot eax = %#lx\n", info->boot_type); +    //debug("boot ebx = %#lx\n", info->boot_data); +    info->boot_type = ELF_BHDR_MAGIC; +    info->boot_data = virt_to_phys(&elf_image_notes); +    debug("boot arg = %#lx\n", info->boot_arg); + +    collect_elfboot_info(info); +#ifdef CONFIG_LINUXBIOS +    collect_linuxbios_info(info); +#endif +#ifdef CONFIG_IMAGE_ELF_MULTIBOOT +    collect_multiboot_info(info); +#endif + +    if (!info->memrange) { +	info->n_memranges = 1; +	info->memrange = malloc(1 * sizeof(struct memrange)); +	info->memrange[0].base = 0; +	info->memrange[0].size = qemu_mem_size; +    } + +    debug("\n"); +    mmap=info->memrange; +    for (i = 0; i < info->n_memranges; i++) { +	debug("%08lx-", (long)mmap[i].base); +	debug("%08lx\n", (long)mmap[i].base + (long)mmap[i].size); +	total += mmap[i].size; +    } +    debug("RAM %ld MB\n", (long)total >> 20); +} diff --git a/roms/openbios/arch/sparc32/tree.fs b/roms/openbios/arch/sparc32/tree.fs new file mode 100644 index 00000000..c82bb171 --- /dev/null +++ b/roms/openbios/arch/sparc32/tree.fs @@ -0,0 +1,114 @@ +include config.fs + +" /" find-device +  2 encode-int " #address-cells" property +  1 encode-int " #size-cells" property + +  " sun4m" encode-string " compatible" property +  h# 0a21fe80 encode-int " clock-frequency" property + +  : encode-unit encode-unit-sbus ; +  : decode-unit decode-unit-sbus ; + +new-device +  " memory" device-name +  external +  : open true ; +  : close ; +  \ claim ( phys size align -- base ) +  \ release ( phys size -- ) +finish-device + +new-device +  " virtual-memory" device-name +  external +  : open true ; +  : close ; +  \ claim ( phys size align -- base ) +  \ release ( phys size -- ) +finish-device + +new-device +  " iommu" device-name +  2 encode-int " #address-cells" property +  1 encode-int " #size-cells" property +  h# 1000 encode-int " page-size" property +  0 encode-int " cache-coherence?" property +  external +  : open ( cr ." opening iommu" cr) true ; +  : close ; +  : encode-unit encode-unit-sbus ; +  : decode-unit decode-unit-sbus ; +finish-device + +" /iommu" find-device +new-device +  " sbus" device-name +  " hierarchical" device-type +  2 encode-int " #address-cells" property +  1 encode-int " #size-cells" property +  h# 01443fd0 encode-int " clock-frequency" property +  h# 1c encode-int " slot-address-bits" property +  h# 3f encode-int " burst-sizes" property +  external +  : open ( cr ." opening SBus" cr) true ; +  : close ; +  : encode-unit encode-unit-sbus ; +  : decode-unit decode-unit-sbus ; +  : map-in map-in-sbus ; +  : map-out map-out-sbus ; +finish-device + +[IFDEF] CONFIG_BPP +" /iommu/sbus" find-device +new-device +  " SUNW,bpp" device-name +  h# 4 encode-int h# 0c800000 encode-int encode+ h# 0000001c encode-int encode+ " reg" property +  h# 33 encode-int 0 encode-int encode+ " intr" property +finish-device +[THEN] + +" /iommu/sbus" find-device +new-device +  " espdma" device-name +  external +  : encode-unit encode-unit-sbus ; +  : decode-unit decode-unit-sbus ; +finish-device + +" /iommu/sbus" find-device +new-device +  " ledma" device-name +  h# 3f encode-int " burst-sizes" property +  external +  : encode-unit encode-unit-sbus ; +  : decode-unit decode-unit-sbus ; +finish-device + +" /iommu/sbus/ledma" find-device +new-device +  " le" device-name +  " network" device-type +  h# 7 encode-int " busmaster-regval" property +  h# 26 encode-int 0 encode-int encode+ " intr" property +finish-device + +\ obio (on-board IO) +" /" find-device +new-device +  " obio" device-name +  " hierarchical" device-type +  2 encode-int " #address-cells" property +  1 encode-int " #size-cells" property +  external +  : open ( cr ." opening obio" cr) true ; +  : close ; +  : encode-unit encode-unit-sbus ; +  : decode-unit decode-unit-sbus ; +finish-device + +" /options" find-device +  " disk" encode-string " boot-from" property + +" /openprom" find-device +  0 0 " aligned-allocator" property diff --git a/roms/openbios/arch/sparc32/udiv.S b/roms/openbios/arch/sparc32/udiv.S new file mode 100644 index 00000000..32753418 --- /dev/null +++ b/roms/openbios/arch/sparc32/udiv.S @@ -0,0 +1,357 @@ +/* $Id: udiv.S,v 1.4 1996/09/30 02:22:38 davem Exp $ + * udiv.S:      This routine was taken from glibc-1.09 and is covered + *              by the GNU Library General Public License Version 2. + */ + + +/* This file is generated from divrem.m4; DO NOT EDIT! */ +/* + * Division and remainder, from Appendix E of the Sparc Version 8 + * Architecture Manual, with fixes from Gordon Irlam. + */ + +/* + * Input: dividend and divisor in %o0 and %o1 respectively. + * + * m4 parameters: + *  .udiv	name of function to generate + *  div		div=div => %o0 / %o1; div=rem => %o0 % %o1 + *  false		false=true => signed; false=false => unsigned + * + * Algorithm parameters: + *  N		how many bits per iteration we try to get (4) + *  WORDSIZE	total number of bits (32) + * + * Derived constants: + *  TOPBITS	number of bits in the top decade of a number + * + * Important variables: + *  Q		the partial quotient under development (initially 0) + *  R		the remainder so far, initially the dividend + *  ITER	number of main division loop iterations required; + *		equal to ceil(log2(quotient) / N).  Note that this + *		is the log base (2^N) of the quotient. + *  V		the current comparand, initially divisor*2^(ITER*N-1) + * + * Cost: + *  Current estimate for non-large dividend is + *	ceil(log2(quotient) / N) * (10 + 7N/2) + C + *  A large dividend is one greater than 2^(31-TOPBITS) and takes a + *  different path, as the upper bits of the quotient must be developed + *  one bit at a time. + */ + + +	.globl .udiv +	.globl _Udiv +.udiv: +_Udiv:	/* needed for export */ + +	! Ready to divide.  Compute size of quotient; scale comparand. +	orcc	%o1, %g0, %o5 +	bne	1f +	 mov	%o0, %o3 + +		! Divide by zero trap.  If it returns, return 0 (about as +		! wrong as possible, but that is what SunOS does...). +		ta	0x2 +		retl +		 clr	%o0 + +1: +	cmp	%o3, %o5			! if %o1 exceeds %o0, done +	blu	Lgot_result		! (and algorithm fails otherwise) +	 clr	%o2 + +	sethi	%hi(1 << (32 - 4 - 1)), %g1 + +	cmp	%o3, %g1 +	blu	Lnot_really_big +	 clr	%o4 + +	! Here the dividend is >= 2**(31-N) or so.  We must be careful here, +	! as our usual N-at-a-shot divide step will cause overflow and havoc. +	! The number of bits in the result here is N*ITER+SC, where SC <= N. +	! Compute ITER in an unorthodox manner: know we need to shift V into +	! the top decade: so do not even bother to compare to R. +	1: +		cmp	%o5, %g1 +		bgeu	3f +		 mov	1, %g7 + +		sll	%o5, 4, %o5 + +		b	1b +		 add	%o4, 1, %o4 + +	! Now compute %g7. +	2: +		addcc	%o5, %o5, %o5 +		bcc	Lnot_too_big +		 add	%g7, 1, %g7 + +		! We get here if the %o1 overflowed while shifting. +		! This means that %o3 has the high-order bit set. +		! Restore %o5 and subtract from %o3. +		sll	%g1, 4, %g1	! high order bit +		srl	%o5, 1, %o5		! rest of %o5 +		add	%o5, %g1, %o5 + +		b	Ldo_single_div +		 sub	%g7, 1, %g7 + +	Lnot_too_big: +	3: +		cmp	%o5, %o3 +		blu	2b +		 nop + +		be	Ldo_single_div +		 nop +	/* NB: these are commented out in the V8-Sparc manual as well */ +	/* (I do not understand this) */ +	! %o5 > %o3: went too far: back up 1 step +	!	srl	%o5, 1, %o5 +	!	dec	%g7 +	! do single-bit divide steps +	! +	! We have to be careful here.  We know that %o3 >= %o5, so we can do the +	! first divide step without thinking.  BUT, the others are conditional, +	! and are only done if %o3 >= 0.  Because both %o3 and %o5 may have the high- +	! order bit set in the first step, just falling into the regular +	! division loop will mess up the first time around. +	! So we unroll slightly... +	Ldo_single_div: +		subcc	%g7, 1, %g7 +		bl	Lend_regular_divide +		 nop + +		sub	%o3, %o5, %o3 +		mov	1, %o2 + +		b	Lend_single_divloop +		 nop +	Lsingle_divloop: +		sll	%o2, 1, %o2 +		bl	1f +		 srl	%o5, 1, %o5 +		! %o3 >= 0 +		sub	%o3, %o5, %o3 +		b	2f +		 add	%o2, 1, %o2 +	1:	! %o3 < 0 +		add	%o3, %o5, %o3 +		sub	%o2, 1, %o2 +	2: +	Lend_single_divloop: +		subcc	%g7, 1, %g7 +		bge	Lsingle_divloop +		 tst	%o3 + +		b,a	Lend_regular_divide + +Lnot_really_big: +1: +	sll	%o5, 4, %o5 + +	cmp	%o5, %o3 +	bleu	1b +	 addcc	%o4, 1, %o4 + +	be	Lgot_result +	 sub	%o4, 1, %o4 + +	tst	%o3	! set up for initial iteration +Ldivloop: +	sll	%o2, 4, %o2 +		! depth 1, accumulated bits 0 +	bl	L.1.16 +	 srl	%o5,1,%o5 +	! remainder is positive +	subcc	%o3,%o5,%o3 +			! depth 2, accumulated bits 1 +	bl	L.2.17 +	 srl	%o5,1,%o5 +	! remainder is positive +	subcc	%o3,%o5,%o3 +			! depth 3, accumulated bits 3 +	bl	L.3.19 +	 srl	%o5,1,%o5 +	! remainder is positive +	subcc	%o3,%o5,%o3 +			! depth 4, accumulated bits 7 +	bl	L.4.23 +	 srl	%o5,1,%o5 +	! remainder is positive +	subcc	%o3,%o5,%o3 +	b	9f +	 add	%o2, (7*2+1), %o2 + +L.4.23: +	! remainder is negative +	addcc	%o3,%o5,%o3 +	b	9f +	 add	%o2, (7*2-1), %o2 + +L.3.19: +	! remainder is negative +	addcc	%o3,%o5,%o3 +			! depth 4, accumulated bits 5 +	bl	L.4.21 +	 srl	%o5,1,%o5 +	! remainder is positive +	subcc	%o3,%o5,%o3 +	b	9f +	 add	%o2, (5*2+1), %o2 + +L.4.21: +	! remainder is negative +	addcc	%o3,%o5,%o3 +	b	9f +	 add	%o2, (5*2-1), %o2 + +L.2.17: +	! remainder is negative +	addcc	%o3,%o5,%o3 +			! depth 3, accumulated bits 1 +	bl	L.3.17 +	 srl	%o5,1,%o5 +	! remainder is positive +	subcc	%o3,%o5,%o3 +			! depth 4, accumulated bits 3 +	bl	L.4.19 +	 srl	%o5,1,%o5 +	! remainder is positive +	subcc	%o3,%o5,%o3 +	b	9f +	 add	%o2, (3*2+1), %o2 + +L.4.19: +	! remainder is negative +	addcc	%o3,%o5,%o3 +	b	9f +	 add	%o2, (3*2-1), %o2 + +L.3.17: +	! remainder is negative +	addcc	%o3,%o5,%o3 +			! depth 4, accumulated bits 1 +	bl	L.4.17 +	 srl	%o5,1,%o5 +	! remainder is positive +	subcc	%o3,%o5,%o3 +	b	9f +	 add	%o2, (1*2+1), %o2 + +L.4.17: +	! remainder is negative +	addcc	%o3,%o5,%o3 +	b	9f +	 add	%o2, (1*2-1), %o2 + +L.1.16: +	! remainder is negative +	addcc	%o3,%o5,%o3 +			! depth 2, accumulated bits -1 +	bl	L.2.15 +	 srl	%o5,1,%o5 +	! remainder is positive +	subcc	%o3,%o5,%o3 +			! depth 3, accumulated bits -1 +	bl	L.3.15 +	 srl	%o5,1,%o5 +	! remainder is positive +	subcc	%o3,%o5,%o3 +			! depth 4, accumulated bits -1 +	bl	L.4.15 +	 srl	%o5,1,%o5 +	! remainder is positive +	subcc	%o3,%o5,%o3 +	b	9f +	 add	%o2, (-1*2+1), %o2 + +L.4.15: +	! remainder is negative +	addcc	%o3,%o5,%o3 +	b	9f +	 add	%o2, (-1*2-1), %o2 + +L.3.15: +	! remainder is negative +	addcc	%o3,%o5,%o3 +			! depth 4, accumulated bits -3 +	bl	L.4.13 +	 srl	%o5,1,%o5 +	! remainder is positive +	subcc	%o3,%o5,%o3 +	b	9f +	 add	%o2, (-3*2+1), %o2 + +L.4.13: +	! remainder is negative +	addcc	%o3,%o5,%o3 +	b	9f +	 add	%o2, (-3*2-1), %o2 + +L.2.15: +	! remainder is negative +	addcc	%o3,%o5,%o3 +			! depth 3, accumulated bits -3 +	bl	L.3.13 +	 srl	%o5,1,%o5 +	! remainder is positive +	subcc	%o3,%o5,%o3 +			! depth 4, accumulated bits -5 +	bl	L.4.11 +	 srl	%o5,1,%o5 +	! remainder is positive +	subcc	%o3,%o5,%o3 +	b	9f +	 add	%o2, (-5*2+1), %o2 + +L.4.11: +	! remainder is negative +	addcc	%o3,%o5,%o3 +	b	9f +	 add	%o2, (-5*2-1), %o2 + +L.3.13: +	! remainder is negative +	addcc	%o3,%o5,%o3 +			! depth 4, accumulated bits -7 +	bl	L.4.9 +	 srl	%o5,1,%o5 +	! remainder is positive +	subcc	%o3,%o5,%o3 +	b	9f +	 add	%o2, (-7*2+1), %o2 + +L.4.9: +	! remainder is negative +	addcc	%o3,%o5,%o3 +	b	9f +	 add	%o2, (-7*2-1), %o2 + +	9: +Lend_regular_divide: +	subcc	%o4, 1, %o4 +	bge	Ldivloop +	 tst	%o3 + +	bl,a	Lgot_result +	! non-restoring fixup here (one instruction only!) +	sub	%o2, 1, %o2 + +Lgot_result: + +	retl +	 mov %o2, %o0 + +	.globl	.udiv_patch +.udiv_patch: +	wr	%g0, 0x0, %y +	nop +	nop +	retl +	 udiv	%o0, %o1, %o0 +	nop diff --git a/roms/openbios/arch/sparc32/vectors.S b/roms/openbios/arch/sparc32/vectors.S new file mode 100644 index 00000000..e812cecb --- /dev/null +++ b/roms/openbios/arch/sparc32/vectors.S @@ -0,0 +1,254 @@ +/* + * <vectors.S> + * + * Sparc V9 Trap Table(s) with SpitFire/Cheetah extensions. + * + *   Copyright (C) 1996, 2001 David S. Miller (davem@caip.rutgers.edu) + * + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License + *   version 2 as published by the Free Software Foundation. + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + *   MA  02110-1301, USA. + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + */ + +#define __ASSEMBLY +#include "psr.h" +#include "asm/asi.h" +#define SER_ADDR5  0x71100004 +#define SER_ADDR10 0xf1100004 + +        .section ".text.vectors", "ax" +        .align 4 /* Should be 16384, but alignment is handled by the ldscript */ +/* Sparc32 trap table */ +        .globl trap_table, t_zero, t_wovf, t_wunf, __divide_error +trap_table: + +#define WINDOW_SPILL \ +        rd %psr, %l0; rd %wim, %l3; b spill_window_entry; nop; + +#define WINDOW_FILL \ +        rd %psr, %l0; rd %wim, %l3; b fill_window_entry; nop; + +#define TRAP_DFAULT(lvl) \ +        rd %psr, %l0; rd %wim, %l3; b handle_dfault; mov lvl, %l7; + +#define BTRAP(lvl) ba bug; mov lvl, %g1; nop; nop; +#define BTRAPS(x) BTRAP(x) BTRAP(x+1) BTRAP(x+2) BTRAP(x+3) BTRAP(x+4) BTRAP(x+5) BTRAP(x+6) BTRAP(x+7) +#define TRAP_ENTRY_INTERRUPT(int_level) \ +        sethi %hi(irq_entry ## int_level), %l7; \ +        or %l7, %lo(irq_entry ## int_level), %l7; \ +        jmp %l7; \ +         nop + +t_zero:         b entry; nop; nop; nop; +                BTRAP(0x1) BTRAP(0x2) BTRAP(0x3) BTRAP(0x4) +t_wovf:         WINDOW_SPILL                        /* Window Overflow               */ +t_wunf:         WINDOW_FILL                         /* Window Underflow              */ +                BTRAP(0x7) +                BTRAP(0x8) +                TRAP_DFAULT(0x9) +                BTRAP(0xa) BTRAP(0xb) BTRAP(0xc) BTRAP(0xd) BTRAP(0xe) BTRAP(0xf) +#if 0 +                BAD_TRAP(0x10) +t_irq1:         TRAP_ENTRY_INTERRUPT(1)             /* IRQ Software/SBUS Level 1     */ +t_irq2:         TRAP_ENTRY_INTERRUPT(2)             /* IRQ SBUS Level 2              */ +t_irq3:         TRAP_ENTRY_INTERRUPT(3)             /* IRQ SCSI/DMA/SBUS Level 3     */ +t_irq4:         TRAP_ENTRY_INTERRUPT(4)             /* IRQ Software Level 4          */ +t_irq5:         TRAP_ENTRY_INTERRUPT(5)             /* IRQ SBUS/Ethernet Level 5     */ +t_irq6:         TRAP_ENTRY_INTERRUPT(6)             /* IRQ Software Level 6          */ +t_irq7:         TRAP_ENTRY_INTERRUPT(7)             /* IRQ Video/SBUS Level 5        */ +t_irq8:         TRAP_ENTRY_INTERRUPT(8)             /* IRQ SBUS Level 6              */ +t_irq9:         TRAP_ENTRY_INTERRUPT(9)             /* IRQ SBUS Level 7              */ +t_irq10:        TRAP_ENTRY_INTERRUPT(10)            /* IRQ Timer #1 (one we use)     */ +t_irq11:        TRAP_ENTRY_INTERRUPT(11)            /* IRQ Floppy Intr.              */ +t_irq12:        TRAP_ENTRY_INTERRUPT(12)            /* IRQ Zilog serial chip         */ +t_irq13:        TRAP_ENTRY_INTERRUPT(13)            /* IRQ Audio Intr.               */ +t_irq14:        TRAP_ENTRY_INTERRUPT(14)            /* IRQ Timer #2                  */ +t_nmi:          BAD_TRAP(0x1f)                      /* Level 15 (NMI)                */ +#else +                BTRAPS(0x10) +                BTRAP(0x18) BTRAP(0x19) +t_irq10:        TRAP_ENTRY_INTERRUPT(10)            /* IRQ Timer #1 (one we use)     */ +                BTRAP(0x1b) BTRAP(0x1c) BTRAP(0x1d) +t_irq14:        TRAP_ENTRY_INTERRUPT(14)            /* IRQ Timer #2                  */ +                BTRAP(0x1f) +#endif +                BTRAPS(0x20) +                BTRAP(0x28) +                TRAP_DFAULT(0x29) +                BTRAP(0x2a) BTRAP(0x2b) BTRAP(0x2c) BTRAP(0x2d) BTRAP(0x2e) BTRAP(0x2f) +                BTRAPS(0x30) BTRAPS(0x38) +                BTRAPS(0x40) BTRAPS(0x48) +                BTRAPS(0x50) BTRAPS(0x58) +                BTRAPS(0x60) BTRAPS(0x68) +                BTRAPS(0x70) BTRAPS(0x78) +                BTRAPS(0x80) BTRAPS(0x88) +                BTRAPS(0x90) BTRAPS(0x98) +                BTRAPS(0xa0) BTRAPS(0xa8) +                BTRAPS(0xb0) BTRAPS(0xb8) +                BTRAPS(0xc0) BTRAPS(0xc8) +                BTRAPS(0xd0) BTRAPS(0xd8) +                BTRAPS(0xe0) BTRAPS(0xe8) +                BTRAPS(0xf0) BTRAPS(0xf8) + +        .section ".text", "ax" +        .align 4 +__divide_error: +bug: +        /* Dump the exception and its context */ +        ! Set up CPU state +        rd      %psr, %g2 +        andn    %g2, PSR_ET, %g2 +        wr      %g2, %psr +        ! Disable mmu, re-enable boot mode +        set     _start, %g3 +        set     dump_exception, %g2 +        sub     %g2, %g3, %g3 +        set     3 << 13, %g2 +        jmp    %g3 +         sta    %g2, [%g0] ASI_M_MMUREGS + +outstr: +        /* void outstr (unsigned long port5, unsigned long port10, +         * const unsigned char *str); +         * Writes a string on an IO port. +         */ +1:      lduba    [%o2] ASI_M_KERNELTXT, %o3 +        cmp     %o3, 0 +        be      2f +         nop +        stba    %o3, [%o0] ASI_M_BYPASS +        stba    %o3, [%o1] ASI_M_CTL +        b       1b +         inc    %o2 +2:      retl +         nop + +outhex: +        /* void outhex (unsigned long port5, unsigned long port10, +         * uint32_t value); +         * Dumps a 32 bits hex number on serial port +         */ +        mov     %o2, %o4 +        set     28, %o3 +        srl     %o4, %o3, %o2 +1:      and     %o2, 0xf, %o2 +        cmp     %o2, 9 +        bgt     2f +         nop +        b       3f +         add    %o2, '0', %o2 +2:      add     %o2, 'a' - 10, %o2 +3:      stba    %o2, [%o0] ASI_M_BYPASS +        stba    %o2, [%o1] ASI_M_CTL +        subcc   %o3, 4, %o3 +        bge     1b +         srl    %o4, %o3, %o2 +        retl +         nop + +        /* void dump_exception (); +         * +         * Dump a message when catching an exception +         */ +dump_exception: +        set     SER_ADDR5 + 2, %o0 +        set     SER_ADDR10 + 2, %o1 +        set     (_BUG_message_0), %o2 +        call    outstr +         nop + +        call    outhex +         mov    %g1, %o2 + +        set     (_BUG_message_1), %o2 +        call    outstr +         nop + +        call    outhex +         mov    %l1, %o2 + +        set     (_BUG_message_2), %o2 +        call    outstr +         nop + +        call    outhex +         mov    %l2, %o2 + +        set     (_BUG_message_3), %o2 +        call    outstr +         nop +_forever: +        /* Loop forever */ +        b       _forever                                  ; +         nop + +irq_entry10: +        sethi   %hi(counter_regs), %l7 +        ld      [%l7 + %lo(counter_regs)], %l7 +        sethi   0x10000, %l6 +        ld      [%l7 + %l6], %g0 +        jmp     %l1 +         rett   %l2 + +irq_entry14: +        sethi   %hi(counter_regs), %l7 +        ld      [%l7 + %lo(counter_regs)], %l7 +        ld      [%l7], %g0 +        sethi   %hi(obp_ticks), %l7 +        ld      [%l7 + %lo(obp_ticks)], %l7 +        ld      [%l7], %l6 +        add     %l6, 10, %l6 +        st      %l6, [%l7] +        jmp     %l1 +         rett  %l2 + +/* Register window handlers */ +#include "wof.S" +#include "wuf.S" + +/* Data fault handler */ +        .data +        .align  4 +        .global ignore_dfault + +ignore_dfault: +        .word   0 + +        .text +        .align  4 + +handle_dfault: +        /* If ignore_dfault is 0, fall through to normal exception handler */ +        sethi   %hi(ignore_dfault), %l4 +        ld      [%l4 + %lo(ignore_dfault)], %l4 +        tst     %l4 +        bz,a    bug +         mov    %l7, %g1 + +        /* Otherwise skip the faulting instruction and return */ +        jmp     %l2 +         rett   %l2 + 4 + + +        .section .rodata +_BUG_message_0: +        .string "Unhandled Exception 0x" +_BUG_message_1: +        .string "\r\nPC = 0x" +_BUG_message_2: +        .string " NPC = 0x" +_BUG_message_3: +        .string "\r\nStopping execution\r\n" diff --git a/roms/openbios/arch/sparc32/wof.S b/roms/openbios/arch/sparc32/wof.S new file mode 100644 index 00000000..8d6bb731 --- /dev/null +++ b/roms/openbios/arch/sparc32/wof.S @@ -0,0 +1,133 @@ +/* + * Proll takes this from Sparclinux kernel, ruthlessly truncated + * because we have no user windows. + * + *   Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License + *   version 2 as published by the Free Software Foundation. + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + *   MA  02110-1301, USA. + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + */ + +// #include <asm/winmacro.h> +// #include <asm/asmmacro.h> + +/* Reg_window offsets */ +#define RW_L0     0x00 +#define RW_L1     0x04 +#define RW_L2     0x08 +#define RW_L3     0x0c +#define RW_L4     0x10 +#define RW_L5     0x14 +#define RW_L6     0x18 +#define RW_L7     0x1c +#define RW_I0     0x20 +#define RW_I1     0x24 +#define RW_I2     0x28 +#define RW_I3     0x2c +#define RW_I4     0x30 +#define RW_I5     0x34 +#define RW_I6     0x38 +#define RW_I7     0x3c + +/* Store the register window onto the 8-byte aligned area starting + * at %reg.  It might be %sp, it might not, we don't care. + */ +#define STORE_WINDOW(reg) \ +	std	%l0, [%reg + RW_L0]; \ +	std	%l2, [%reg + RW_L2]; \ +	std	%l4, [%reg + RW_L4]; \ +	std	%l6, [%reg + RW_L6]; \ +	std	%i0, [%reg + RW_I0]; \ +	std	%i2, [%reg + RW_I2]; \ +	std	%i4, [%reg + RW_I4]; \ +	std	%i6, [%reg + RW_I6]; + +/* We define macro's for registers which have a fixed + * meaning throughout this entire routine.  The 'T' in + * the comments mean that the register can only be + * accessed when in the 'trap' window, 'G' means + * accessible in any window.  Do not change these registers + * after they have been set, until you are ready to return + * from the trap. + */ +#define t_psr       l0 /* %psr at trap time                     T */ +#define t_pc        l1 /* PC for trap return                    T */ +#define t_npc       l2 /* NPC for trap return                   T */ +#define t_wim       l3 /* %wim at trap time                     T */ +#define saved_g5    l5 /* Global save register                  T */ +#define saved_g6    l6 /* Global save register                  T */ + +/* Now registers whose values can change within the handler.      */ +#define twin_tmp    l4 /* Temp reg, only usable in trap window  T */ +#define glob_tmp    g5 /* Global temporary reg, usable anywhere G */ + +	.text +	.align	4 + +	/* BEGINNING OF PATCH INSTRUCTIONS */ +	/* On a 7-window Sparc the boot code patches spnwin_* +	 * instructions with the following ones. +	 */ +	.globl	spnwin_patch1_7win, spnwin_patch2_7win, spnwin_patch3_7win +spnwin_patch1_7win:	sll	%t_wim, 6, %glob_tmp +spnwin_patch2_7win:	and	%glob_tmp, 0x7f, %glob_tmp +spnwin_patch3_7win:	and	%twin_tmp, 0x7f, %twin_tmp +	/* END OF PATCH INSTRUCTIONS */ + +	/* The trap entry point has done the following: +	 * +	 * rd    %psr, %l0 +	 * rd    %wim, %l3 +	 * b     spill_window_entry +	 * nop +	 */ + +	.globl	spill_window_entry +	.globl	spnwin_patch1, spnwin_patch2 +spill_window_entry: +	/* LOCATION: Trap Window */ + +	mov	%g5, %saved_g5		! save away global temp register +	mov	%g6, %saved_g6		! save away 'current' ptr register + +	/* Compute what the new %wim will be if we save the +	 * window properly in this trap handler. +	 * +	 * newwim = ((%wim>>1) | (%wim<<(nwindows - 1))); +	 */ +		srl	%t_wim, 0x1, %twin_tmp +spnwin_patch1:	sll	%t_wim, 7, %glob_tmp +		or	%glob_tmp, %twin_tmp, %glob_tmp +spnwin_patch2:	and	%glob_tmp, 0xff, %glob_tmp + +	/* Save into the window which must be saved and do it. +	 */ +	save	%g0, %g0, %g0		! save into the window to stash away +	wr	%glob_tmp, 0x0, %wim	! set new %wim, this is safe now + +	/* LOCATION: Window to be saved */ + +	STORE_WINDOW(sp)		! stash the window +	restore	%g0, %g0, %g0		! go back into trap window + +	/* LOCATION: Trap window */ +	mov	%saved_g5, %g5		! restore %glob_tmp +	mov	%saved_g6, %g6		! restore %curptr +	wr	%t_psr, 0x0, %psr	! restore condition codes in %psr +	nop; nop; nop			! waste some time +	jmp	%t_pc			! Return from trap +	rett	%t_npc			! we are done diff --git a/roms/openbios/arch/sparc32/wuf.S b/roms/openbios/arch/sparc32/wuf.S new file mode 100644 index 00000000..853fc732 --- /dev/null +++ b/roms/openbios/arch/sparc32/wuf.S @@ -0,0 +1,154 @@ +/* + * Window fill (underflow) trap, based on code from Sparclinux. + * + * Copyright (C) 1995 David S. Miller + * + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License + *   version 2 as published by the Free Software Foundation. + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + *   MA  02110-1301, USA. + */ + +// #include <psr.h> +// #include <asi.h> + +/* Reg_window offsets */ +#define RW_L0     0x00 +#define RW_L1     0x04 +#define RW_L2     0x08 +#define RW_L3     0x0c +#define RW_L4     0x10 +#define RW_L5     0x14 +#define RW_L6     0x18 +#define RW_L7     0x1c +#define RW_I0     0x20 +#define RW_I1     0x24 +#define RW_I2     0x28 +#define RW_I3     0x2c +#define RW_I4     0x30 +#define RW_I5     0x34 +#define RW_I6     0x38 +#define RW_I7     0x3c + +/* Load a register window from the area beginning at %reg. */ +#define LOAD_WINDOW(reg) \ +	ldd	[%reg + RW_L0], %l0; \ +	ldd	[%reg + RW_L2], %l2; \ +	ldd	[%reg + RW_L4], %l4; \ +	ldd	[%reg + RW_L6], %l6; \ +	ldd	[%reg + RW_I0], %i0; \ +	ldd	[%reg + RW_I2], %i2; \ +	ldd	[%reg + RW_I4], %i4; \ +	ldd	[%reg + RW_I6], %i6; + +#define WRITE_PAUSE	nop; nop; nop; /* Have to do this after %wim/%psr chg */ + +/* Just like the overflow handler we define macros for registers + * with fixed meanings in this routine. + */ +#define t_psr       l0 +#define t_pc        l1 +#define t_npc       l2 +#define t_wim       l3 +/* Don't touch the above registers or else you die horribly... */ + +/* Now macros for the available scratch registers in this routine. */ +#define twin_tmp1    l4 +#define twin_tmp2    l5 + +	.text +	.align	4 + +	/* The trap entry point has executed the following: +	 * +	 * rd    %psr, %l0 +	 * rd    %wim, %l3 +	 * b     fill_window_entry +	 * andcc %l0, PSR_PS, %g0 +	 */ + +	/* To get an idea of what has just happened to cause this +	 * trap take a look at this diagram: +	 * +	 *      1  2  3  4     <--  Window number +	 *      ---------- +	 *      T  O  W  I     <--  Symbolic name +	 * +	 *      O == the window that execution was in when +	 *           the restore was attempted +	 * +	 *      T == the trap itself has save'd us into this +	 *           window +	 * +	 *      W == this window is the one which is now invalid +	 *           and must be made valid plus loaded from the +	 *           stack +	 * +	 *      I == this window will be the invalid one when we +	 *           are done and return from trap if successful +	 */ + +	/* BEGINNING OF PATCH INSTRUCTIONS */ + +	/* On 7-window Sparc the boot code patches fnwin_patch1 +	 * with the following instruction. +	 */ +	.globl	fnwin_patch1_7win, fnwin_patch2_7win +fnwin_patch1_7win:	srl	%t_wim, 6, %twin_tmp2 +fnwin_patch2_7win:	and	%twin_tmp1, 0x7f, %twin_tmp1 +	/* END OF PATCH INSTRUCTIONS */ + + +	.globl	fill_window_entry, fnwin_patch1, fnwin_patch2 +fill_window_entry: +	/* LOCATION: Window 'T' */ + +	/* Compute what the new %wim is going to be if we retrieve +	 * the proper window off of the stack. +	 */ +		sll	%t_wim, 1, %twin_tmp1 +fnwin_patch1:	srl	%t_wim, 7, %twin_tmp2 +		or	%twin_tmp1, %twin_tmp2, %twin_tmp1 +fnwin_patch2:	and	%twin_tmp1, 0xff, %twin_tmp1 + +	wr	%twin_tmp1, 0x0, %wim	/* Make window 'I' invalid */ + +	restore	%g0, %g0, %g0		/* Restore to window 'O' */ + +	/* Trapped from kernel, we trust that the kernel does not +	 * 'over restore' sorta speak and just grab the window +	 * from the stack and return.  Easy enough. +	 */ +	/* LOCATION: Window 'O' */ + +	restore %g0, %g0, %g0 +        WRITE_PAUSE + +	/* LOCATION: Window 'W' */ + +	LOAD_WINDOW(sp)	                /* Load it up */ + +	/* Spin the wheel... */ +	save	%g0, %g0, %g0 +	save	%g0, %g0, %g0 +	/* I'd like to buy a vowel please... */ + +	/* LOCATION: Window 'T' */ + +	/* Now preserve the condition codes in %psr, pause, and +	 * return from trap.  This is the simplest case of all. +	 */ +	wr	%t_psr, 0x0, %psr +	WRITE_PAUSE + +	jmp	%t_pc +	rett	%t_npc  | 
