Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / arch / sparc32 / boot.c
diff --git a/qemu/roms/openbios/arch/sparc32/boot.c b/qemu/roms/openbios/arch/sparc32/boot.c
new file mode 100644 (file)
index 0000000..49ec4cf
--- /dev/null
@@ -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);
+        }
+}