]> git.ozlabs.org Git - yaboot.git/blobdiff - second/yaboot.c
Try harder to allocate malloc region
[yaboot.git] / second / yaboot.c
index 3fbb103ab4d942134be70c0855ceda1b58f7cb24..9b499b96cb014fc063bd5cd0b2ecef24a5214ccf 100644 (file)
@@ -112,6 +112,8 @@ static void     setup_display(void);
 
 int useconf = 0;
 char bootdevice[BOOTDEVSZ];
 
 int useconf = 0;
 char bootdevice[BOOTDEVSZ];
+char bootoncelabel[1024];
+char bootargs[1024];
 char *password = NULL;
 struct boot_fspec_t boot;
 int _machine = _MACH_Pmac;
 char *password = NULL;
 struct boot_fspec_t boot;
 int _machine = _MACH_Pmac;
@@ -176,6 +178,7 @@ yaboot_start (unsigned long r3, unsigned long r4, unsigned long r5)
 {
      int result;
      void* malloc_base = NULL;
 {
      int result;
      void* malloc_base = NULL;
+     unsigned long addr;
      prom_handle root;
 
      /* OF seems to do it, but I'm not very confident */
      prom_handle root;
 
      /* OF seems to do it, but I'm not very confident */
@@ -194,7 +197,10 @@ yaboot_start (unsigned long r3, unsigned long r4, unsigned long r5)
      prom_init ((prom_entry) r5);
 
      /* Allocate some memory for malloc'ator */
      prom_init ((prom_entry) r5);
 
      /* Allocate some memory for malloc'ator */
-     malloc_base = prom_claim((void *)MALLOCADDR, MALLOCSIZE, 0);
+     for (addr = MALLOCADDR; addr <= MALLOCADDR * 16 ;addr+=0x100000) {
+         malloc_base = prom_claim((void *)addr, MALLOCSIZE, 0);
+         if (malloc_base != (void *)-1) break;
+     }
      if (malloc_base == (void *)-1) {
          prom_printf("Can't claim malloc buffer (%d bytes at 0x%08x)\n",
                      MALLOCSIZE, MALLOCADDR);
      if (malloc_base == (void *)-1) {
          prom_printf("Can't claim malloc buffer (%d bytes at 0x%08x)\n",
                      MALLOCSIZE, MALLOCADDR);
@@ -324,13 +330,11 @@ done:
  * config file. Handle the "\\" (blessed system folder)
  */
 static int
  * config file. Handle the "\\" (blessed system folder)
  */
 static int
-load_config_file(struct boot_fspec_t *orig_fspec)
+load_config_file(struct boot_fspec_t *fspec)
 {
      char *conf_file = NULL, *p;
      struct boot_file_t file;
      int sz, opened = 0, result = 0;
 {
      char *conf_file = NULL, *p;
      struct boot_file_t file;
      int sz, opened = 0, result = 0;
-     char conf_path[512];
-     struct boot_fspec_t fspec = *orig_fspec;
 
      /* Allocate a buffer for the config file */
      conf_file = malloc(CONFIG_FILE_MAX);
 
      /* Allocate a buffer for the config file */
      conf_file = malloc(CONFIG_FILE_MAX);
@@ -339,22 +343,11 @@ load_config_file(struct boot_fspec_t *orig_fspec)
          goto bail;
      }
 
          goto bail;
      }
 
-     /* Build the path to the file */
-     if (_machine == _MACH_chrp)
-         strcpy(conf_path, "/etc/");
-     else
-         conf_path[0] = 0;
-     if (fspec.file && *fspec.file)
-         strcat(conf_path, fspec.file);
-     else
-     strcat(conf_path, CONFIG_FILE_NAME);
-
      /* Open it */
      /* Open it */
-     fspec.file = conf_path;
-     result = open_file(&fspec, &file);
+     result = open_file(fspec, &file);
      if (result != FILE_ERR_OK) {
      if (result != FILE_ERR_OK) {
-         prom_printf("%s:%d,", fspec.dev, fspec.part);
-         prom_perror(result, fspec.file);
+         prom_printf("%s:%d,", fspec->dev, fspec->part);
+         prom_perror(result, fspec->file);
          prom_printf("Can't open config file\n");
          goto bail;
      }
          prom_printf("Can't open config file\n");
          goto bail;
      }
@@ -374,11 +367,27 @@ load_config_file(struct boot_fspec_t *orig_fspec)
      opened = 0;
 
      /* Call the parsing code in cfg.c */
      opened = 0;
 
      /* Call the parsing code in cfg.c */
-     if (cfg_parse(conf_path, conf_file, sz) < 0) {
+     if (cfg_parse(fspec->file, conf_file, sz) < 0) {
          prom_printf ("Syntax error or read error config\n");
          goto bail;
      }
 
          prom_printf ("Syntax error or read error config\n");
          goto bail;
      }
 
+     /* 
+      * set the default cf_option to label that has the same MAC addr 
+      * it only works if there is a label with the MAC addr on yaboot.conf
+      */
+     if (prom_get_devtype(fspec->dev) == FILE_DEVICE_NET) {
+         /* change the variable bellow to get the MAC dinamicaly */
+         char * macaddr = NULL;
+         int default_mac = 0;
+
+         macaddr = prom_get_mac(prom_get_netinfo());
+         default_mac = cfg_set_default_by_mac(macaddr);
+         if (default_mac >= 1) {
+            prom_printf("Default label was changed to macaddr label.\n");
+         }
+     }
+
      DEBUG_F("Config file successfully parsed, %d bytes\n", sz);
 
      /* Now, we do the initialisations stored in the config file */
      DEBUG_F("Config file successfully parsed, %d bytes\n", sz);
 
      /* Now, we do the initialisations stored in the config file */
@@ -440,35 +449,6 @@ bail:
      return result;
 }
 
      return result;
 }
 
-/*
- * "bootp-response" is the property name which is specified in
- * the recommended practice doc for obp-tftp. However, pmac
- * provides a "dhcp-response" property and chrp provides a
- * "bootpreply-packet" property.  The latter appears to begin the
- * bootp packet at offset 0x2a in the property for some reason.
- */
-
-struct bootp_property_offset {
-     char *name; /* property name */
-     int offset; /* offset into property where bootp packet occurs */
-};
-static const struct bootp_property_offset bootp_response_properties[] = {
-     { .name = "bootp-response", .offset = 0 },
-     { .name = "dhcp-response", .offset = 0 },
-     { .name = "bootpreply-packet", .offset = 0x2a },
-};
-
-struct bootp_packet {
-     u8 op, htype, hlen, hops;
-     u32 xid;
-     u16 secs, flags;
-     u32 ciaddr, yiaddr, siaddr, giaddr;
-     unsigned char chaddr[16];
-     unsigned char sname[64];
-     unsigned char file[128];
-     /* vendor options go here if we need them */
-};
-
 /*
  * Search for config file by MAC address, then by IP address.
  * Basically copying pxelinux's algorithm.
 /*
  * Search for config file by MAC address, then by IP address.
  * Basically copying pxelinux's algorithm.
@@ -476,84 +456,45 @@ struct bootp_packet {
  */
 static int load_my_config_file(struct boot_fspec_t *orig_fspec)
 {
  */
 static int load_my_config_file(struct boot_fspec_t *orig_fspec)
 {
-     void *bootp_response = NULL;
-     char *propname;
      struct bootp_packet *packet;
      struct bootp_packet *packet;
-     int i = 0, size, offset = 0, rc = 0;
-     prom_handle chosen;
+     int rc = 0;
      struct boot_fspec_t fspec = *orig_fspec;
      struct boot_fspec_t fspec = *orig_fspec;
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+     char *cfgpath = (_machine == _MACH_chrp) ? "/etc/" : "";
+     int flen;
+     int minlen;
 
 
-     chosen = prom_finddevice("/chosen");
-     if (chosen < 0) {
-          prom_printf("chosen=%d\n", chosen);
-         return 0;
-     }
-
-     for (i = 0; i < ARRAY_SIZE(bootp_response_properties); i++) {
-         propname = bootp_response_properties[i].name;
-         size = prom_getproplen(chosen, propname);
-         if (size <= 0)
-              continue;
-
-         DEBUG_F("using /chosen/%s\n", propname);
-         offset = bootp_response_properties[i].offset;
-         break;
-     }
-
-     if (size <= 0)
-         goto out;
-
-     if (sizeof(*packet) > size - offset) {
-         prom_printf("Malformed %s property?\n", propname);
-         goto out;
-     }
-
-     bootp_response = malloc(size);
-     if (!bootp_response)
-         goto out;
-
-     if (prom_getprop(chosen, propname, bootp_response, size) < 0)
-         goto out;
-
-     packet = bootp_response + offset;
+     packet = prom_get_netinfo();
 
      /*
       * First, try to match on mac address with the hardware type
       * prepended.
       */
 
 
      /*
       * First, try to match on mac address with the hardware type
       * prepended.
       */
 
-     /* 3 chars per byte in chaddr + 2 chars for htype + \0 */
-     fspec.file = malloc(packet->hlen * 3 + 2 + 1);
+     /* 3 chars per byte in chaddr + 2 chars for htype + /etc/ +\0 */
+     fspec.file = malloc(packet->hlen * 3 + 2 + 6);
      if (!fspec.file)
          goto out;
 
      if (!fspec.file)
          goto out;
 
-     sprintf(fspec.file, "%02x", packet->htype);
-
-     for (i = 0; i < packet->hlen; i++) {
-         char tmp[4];
-         sprintf(tmp, "-%02x", packet->chaddr[i]);
-         strcat(fspec.file, tmp);
-     }
+     sprintf(fspec.file, "%s%02x-", cfgpath, packet->htype);
+     strcat(fspec.file, prom_get_mac(packet));
 
      rc = load_config_file(&fspec);
      if (rc)
          goto out;
 
 
      rc = load_config_file(&fspec);
      if (rc)
          goto out;
 
-
      /*
       * Now try to match on IP.
       */
      /*
       * Now try to match on IP.
       */
-     free(fspec.file);
-     fspec.file = malloc(9);
-     sprintf(fspec.file, "%08X", packet->yiaddr);
+     /* no need to realloc for /etc/ + 8 chars in yiaddr + \0 */
+     sprintf(fspec.file, "%s%s", cfgpath, prom_get_ip(packet));
 
 
-     while (strlen(fspec.file)) {
+     for (flen = strlen(fspec.file),
+          minlen = strlen(cfgpath); flen > minlen; flen--) {
          rc = load_config_file(&fspec);
          if (rc)
               goto out;
          /* Chop one digit off the end, try again */
          rc = load_config_file(&fspec);
          if (rc)
               goto out;
          /* Chop one digit off the end, try again */
-         fspec.file[strlen(fspec.file) - 1] = '\0';
+         fspec.file[flen - 1] = '\0';
      }
 
  out:
      }
 
  out:
@@ -561,7 +502,6 @@ static int load_my_config_file(struct boot_fspec_t *orig_fspec)
          orig_fspec->file = fspec.file;
      else
          free(fspec.file);
          orig_fspec->file = fspec.file;
      else
          free(fspec.file);
-     free(bootp_response);
      return rc;
 }
 
      return rc;
 }
 
@@ -706,6 +646,7 @@ int get_params(struct boot_param_t* params)
 {
      int defpart;
      char *defdevice = 0;
 {
      int defpart;
      char *defdevice = 0;
+     char defdevice_bak[1024];
      char *p, *q, *endp;
      int c, n;
      char *imagename = 0, *label;
      char *p, *q, *endp;
      int c, n;
      char *imagename = 0, *label;
@@ -714,10 +655,11 @@ int get_params(struct boot_param_t* params)
      int singlekey = 0;
      int restricted = 0;
      static int first = 1;
      int singlekey = 0;
      int restricted = 0;
      static int first = 1;
-     static char bootargs[1024];
      static char imagepath[1024];
      static char initrdpath[1024];
      static char sysmappath[1024];
      static char imagepath[1024];
      static char initrdpath[1024];
      static char sysmappath[1024];
+     static char manualinitrd[1024];
+     static int definitrd = 1, hasarg = 0;
 
      pause_after = 0;
      memset(params, 0, sizeof(*params));
 
      pause_after = 0;
      memset(params, 0, sizeof(*params));
@@ -731,7 +673,6 @@ int get_params(struct boot_param_t* params)
 
      if (first) {
          first = 0;
 
      if (first) {
          first = 0;
-         prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
          imagename = bootargs;
          word_split(&imagename, &params->args);
          timeout = DEFAULT_TIMEOUT;
          imagename = bootargs;
          word_split(&imagename, &params->args);
          timeout = DEFAULT_TIMEOUT;
@@ -778,8 +719,12 @@ int get_params(struct boot_param_t* params)
      }
 
      if (c == '\n' || c == '\r') {
      }
 
      if (c == '\n' || c == '\r') {
-         if (!imagename)
-              imagename = cfg_get_default();
+         if (!imagename) {
+              if (bootoncelabel[0] != 0)
+                   imagename = bootoncelabel;
+              else
+                   imagename = cfg_get_default();
+         }
          if (imagename)
               prom_printf("%s", imagename);
          if (params->args)
          if (imagename)
               prom_printf("%s", imagename);
          if (params->args)
@@ -794,6 +739,46 @@ int get_params(struct boot_param_t* params)
          word_split(&imagename, &params->args);
      }
 
          word_split(&imagename, &params->args);
      }
 
+     /* initrd setup via cmd console */
+     /* first, check if the user uses it with some label */
+     if (!strncmp(params->args, "initrd=", 7)) {
+         DEBUG_F("params->args: %s\n", params->args);
+         definitrd = 0;
+     }
+     /* after, check if there is the 'initrd=' in the imagename string */
+     if (!strncmp(imagename, "initrd=", 7) || !definitrd) {
+
+         /* return the value of definitrd to 1 */
+         if (!definitrd)
+             definitrd = 1;
+
+         /* args = "initrd=blah" */
+         char *args = NULL;
+
+         if (params->args) {
+            args = params->args;
+            params->args = NULL;
+            hasarg = 1;
+         } else
+            args = imagename;
+
+         if (strlen(args)){
+             /* copy the string after the '=' to manualinitrd */
+             strcpy(manualinitrd, args+7);
+             definitrd = 0;
+             prom_printf("New initrd file specified: %s\n", manualinitrd);
+         } else {
+             prom_printf("ERROR: no initrd specified!\n");
+             return 0;
+         }
+
+         /* set imagename with the default values of the config file */
+         if ((prom_get_devtype(boot.dev) == FILE_DEVICE_NET) && !hasarg)
+             imagename = cfg_get_default();
+         else
+             imagename = cfg_get_default();
+     }
+
      /* chrp gets this wrong, force it -- Cort */
      if ( useconf && (!imagename || imagename[0] == 0 ))
          imagename = cfg_get_default();
      /* chrp gets this wrong, force it -- Cort */
      if ( useconf && (!imagename || imagename[0] == 0 ))
          imagename = cfg_get_default();
@@ -801,6 +786,8 @@ int get_params(struct boot_param_t* params)
      label = 0;
      defdevice = boot.dev;
 
      label = 0;
      defdevice = boot.dev;
 
+     strcpy(defdevice_bak,defdevice);
+
      if (useconf) {
          defdevice = cfg_get_strg(0, "device");
          p = cfg_get_strg(0, "partition");
      if (useconf) {
          defdevice = cfg_get_strg(0, "device");
          p = cfg_get_strg(0, "partition");
@@ -853,10 +840,21 @@ int get_params(struct boot_param_t* params)
               "resides on, and \"partno\" is the partition number the image resides on.\n"
               "Note that the comma (,) is only required if you specify an OpenFirmware\n"
               "device, if you only specify a filename you should not start it with a \",\"\n\n"
               "resides on, and \"partno\" is the partition number the image resides on.\n"
               "Note that the comma (,) is only required if you specify an OpenFirmware\n"
               "device, if you only specify a filename you should not start it with a \",\"\n\n"
-              "If you omit \"device:\" and \"partno\" yaboot will use the values of \n"
-              "\"device=\" and \"partition=\" in yaboot.conf, right now those are set to: \n"
-              "device=%s\n"
-              "partition=%d\n\n", defdevice, defpart);
+           "To boot a alternative initrd file rather than specified in the yaboot\n"
+           "configuration file, use the \"initrd\" command on Yaboot's prompt: \n"
+           "\"initrd=[name.img]\". This will load the \"name.img\" file after the default\n"
+           "kernel image. You can, also, specify a different initrd file to any other\n"
+           "label of the yaboot configuration file. Just type \"label initrd=[name.img]\"\n"
+           "and the specified initrd file will be loaded.\n\n"
+              "To load an alternative config file rather than /etc/yaboot.conf, enter\n"
+              "its device, partno and path, on Open Firmware Prompt:\n"
+              "boot conf=device:partno,/path/to/configfile\n."
+              "To reload the config file or load a new one, use the \"conf\" command\n"
+              "on Yaboot's prompt:\n"
+              "conf [device=device] [partition=partno] [file=/path/to/configfile]\n\n"
+              "If you omit \"device\" and \"partno\", Yaboot will use their current\n"
+              "values. You can check them by entering \"conf\" on Yaboot's prompt.\n");
+
          return 0;
      }
 
          return 0;
      }
 
@@ -874,6 +872,91 @@ int get_params(struct boot_param_t* params)
          return 1;
      }
 
          return 1;
      }
 
+     if (!strncmp (imagename, "conf", 4)) {
+
+         // imagename = "conf file=blah dev=bleh part=blih"
+         DEBUG_F("Loading user-specified config file: %s\n",imagename);
+         if (password) {
+             check_password ("Restricted command.");
+             return 1;
+         }
+
+         // args= "file=blah dev=bleh part=blih"
+         char *args = params->args;
+
+         if (strlen(args)){
+
+            // set a pointer to the first space in args
+            char *space = strchr(args,' ');
+
+            int loop = 3;
+            while (loop > 0){
+                char temp[1024] = "0";
+
+                // copy next argument to temp
+                strncpy(temp, args, space-args);
+
+                // parse temp and set boot arguments
+                if (!strncmp (temp, "file=", 5)){
+                   DEBUG_F("conf file: %s\n", temp+5);
+                   strcpy(boot.file, temp+5);
+                } else if (!strncmp (temp, "device=", 7)){
+                   DEBUG_F("conf device: %s\n", temp+7);
+                   strcpy(boot.dev, temp+7);
+                } else if (!strncmp (temp, "partition=", 10)){
+                   DEBUG_F("conf partition: %s\n", temp+10);
+                   boot.part=simple_strtol(temp+10,NULL,10);
+                } else
+                   space = NULL;
+
+                // set the pointer to the next space in args;
+                // set the loop control variable
+                if (strlen(space)>1){
+                    // Go to the next argument
+                    args = space+1;
+
+                    loop--;
+                    if (strchr(args,' ') == NULL)
+                        space = &args[strlen(args)];
+                    else
+                        space = strchr(args,' ');
+                } else {
+                    loop = -1;
+                    space = NULL;
+                }
+            }
+
+            prom_printf("Loading config file...\n");
+            useconf = load_config_file(&boot);
+            if (useconf > 0){
+                if ((q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
+                   timeout = simple_strtol(q, NULL, 0);
+            } else {
+               prom_printf("Restoring default values.\n");
+               strcpy(boot.file,"");
+               strcpy(boot.dev, defdevice_bak);
+               boot.part = defpart;
+            }
+
+         } else {
+             prom_printf("Current configuration:\n");
+             prom_printf("device: %s\n", boot.dev);
+             if (boot.part < 0)
+                 prom_printf("partition: auto\n");
+             else
+                 prom_printf("partition: %d\n", boot.part);
+             if (strlen(boot.file))
+                 prom_printf("file: %s\n", boot.file);
+             else
+                 prom_printf("file: /etc/%s\n",CONFIG_FILE_NAME);
+         }
+
+         imagename = "\0";
+         params->args = "\0";
+
+         return 0;
+     }
+
      if (imagename[0] == '$') {
          /* forth command string */
          if (password)
      if (imagename[0] == '$') {
          /* forth command string */
          if (password)
@@ -892,14 +975,22 @@ int get_params(struct boot_param_t* params)
          prom_printf("%s: Unable to parse\n", imagepath);
          return 0;
      }
          prom_printf("%s: Unable to parse\n", imagepath);
          return 0;
      }
-     DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev,
-            params->kernel.part, params->kernel.file);
-
+     DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev, params->kernel.part, params->kernel.file);
      if (useconf) {
          p = cfg_get_strg(label, "initrd");
          if (p && *p) {
      if (useconf) {
          p = cfg_get_strg(label, "initrd");
          if (p && *p) {
-              DEBUG_F("Parsing initrd path <%s>\n", p);
-              strncpy(initrdpath, p, 1024);
+
+           /* check if user seted to use a initrd file from boot console */
+           if (!definitrd && p != manualinitrd) {
+               if (manualinitrd[0] != "/" && (prom_get_devtype(defdevice_bak) != FILE_DEVICE_NET)) {
+                   strcpy(initrdpath, "/");
+                   strcat(initrdpath, manualinitrd);
+               } else
+                   strncpy(initrdpath, manualinitrd, 1024);
+           } else
+               strncpy(initrdpath, p, 1024);
+
+              DEBUG_F("Parsing initrd path <%s>\n", initrdpath);
               if (!parse_device_path(initrdpath, defdevice, defpart,
                                      "/root.bin", &params->rd)) {
                    prom_printf("%s: Unable to parse\n", imagepath);
               if (!parse_device_path(initrdpath, defdevice, defpart,
                                      "/root.bin", &params->rd)) {
                    prom_printf("%s: Unable to parse\n", imagepath);
@@ -1202,7 +1293,7 @@ load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
      Elf32_Ehdr                *e = &(loadinfo->elf.elf32hdr);
      Elf32_Phdr                *p, *ph;
      int                       size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
      Elf32_Ehdr                *e = &(loadinfo->elf.elf32hdr);
      Elf32_Phdr                *p, *ph;
      int                       size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
-     unsigned long     addr, loadaddr;
+     unsigned long     loadaddr;
 
      /* Read the rest of the Elf header... */
      if ((*(file->fs->read))(file, size, &e->e_version) < size) {
 
      /* Read the rest of the Elf header... */
      if ((*(file->fs->read))(file, size, &e->e_version) < size) {
@@ -1290,13 +1381,7 @@ load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
           loadaddr = loadinfo->load_loc;
      }
 
           loadaddr = loadinfo->load_loc;
      }
 
-     /* On some systems, loadaddr may already be claimed, so try some
-      * other nearby addresses before giving up.
-      */
-     for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
-         loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
-         if (loadinfo->base != (void *)-1) break;
-     }
+     loadinfo->base = prom_claim_chunk((void *)loadaddr, loadinfo->memsize, 0);
      if (loadinfo->base == (void *)-1) {
          prom_printf("Claim error, can't allocate kernel memory\n");
          goto bail;
      if (loadinfo->base == (void *)-1) {
          prom_printf("Claim error, can't allocate kernel memory\n");
          goto bail;
@@ -1346,7 +1431,7 @@ load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
      Elf64_Ehdr                *e = &(loadinfo->elf.elf64hdr);
      Elf64_Phdr                *p, *ph;
      int                       size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
      Elf64_Ehdr                *e = &(loadinfo->elf.elf64hdr);
      Elf64_Phdr                *p, *ph;
      int                       size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
-     unsigned long     addr, loadaddr;
+     unsigned long     loadaddr;
 
      /* Read the rest of the Elf header... */
      if ((*(file->fs->read))(file, size, &e->e_version) < size) {
 
      /* Read the rest of the Elf header... */
      if ((*(file->fs->read))(file, size, &e->e_version) < size) {
@@ -1434,13 +1519,7 @@ load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
           loadaddr = e->e_entry;
      }
 
           loadaddr = e->e_entry;
      }
 
-     /* On some systems, loadaddr may already be claimed, so try some
-      * other nearby addresses before giving up.
-      */
-     for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
-         loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
-         if (loadinfo->base != (void *)-1) break;
-     }
+     loadinfo->base = prom_claim_chunk((void *)loadaddr, loadinfo->memsize, 0);
      if (loadinfo->base == (void *)-1) {
          prom_printf("Claim error, can't allocate kernel memory\n");
          goto bail;
      if (loadinfo->base == (void *)-1) {
          prom_printf("Claim error, can't allocate kernel memory\n");
          goto bail;
@@ -1559,7 +1638,7 @@ setup_display(void)
      }
 
      if (scrn == PROM_INVALID_HANDLE) {
      }
 
      if (scrn == PROM_INVALID_HANDLE) {
-         prom_printf("No screen device found !/n");
+         prom_printf("No screen device found !\n");
          return;
      }
      for(i=0;i<16;i++) {
          return;
      }
      for(i=0;i<16;i++) {
@@ -1594,12 +1673,38 @@ int
 yaboot_main(void)
 {
      char *ptype;
 yaboot_main(void)
 {
      char *ptype;
+     int conf_given = 0;
+     char conf_path[1024];
 
      if (_machine == _MACH_Pmac)
          setup_display();
 
 
      if (_machine == _MACH_Pmac)
          setup_display();
 
+     prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
+     DEBUG_F("/chosen/bootargs = %s\n", bootargs);
      prom_get_chosen("bootpath", bootdevice, BOOTDEVSZ);
      DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
      prom_get_chosen("bootpath", bootdevice, BOOTDEVSZ);
      DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
+
+     /* If conf= specified on command line, it overrides
+        Usage: conf=device:partition,/path/to/conffile
+        Example: On Open Firmware Prompt, type
+                 boot conf=/pci@8000000f8000000/pci@1/pci1014,028C@1/scsi@0/sd@1,0:3,/etc/yaboot.conf */
+
+     if (!strncmp(bootargs, "conf=", 5)) {
+        DEBUG_F("Using conf argument in Open Firmware\n");
+        char *end = strchr(bootargs,' ');
+        if (end)
+            *end = 0;
+
+        strcpy(bootdevice, bootargs + 5);
+        conf_given = 1;
+        DEBUG_F("Using conf=%s\n", bootdevice);
+
+        /* Remove conf=xxx from bootargs */
+        if (end)
+            memmove(bootargs, end+1, strlen(end+1)+1);
+        else
+            bootargs[0] = 0;
+     }
      if (bootdevice[0] == 0) {
          prom_get_options("boot-device", bootdevice, BOOTDEVSZ);
          DEBUG_F("boot-device = %s\n", bootdevice);
      if (bootdevice[0] == 0) {
          prom_get_options("boot-device", bootdevice, BOOTDEVSZ);
          DEBUG_F("boot-device = %s\n", bootdevice);
@@ -1609,6 +1714,14 @@ yaboot_main(void)
          return -1;
      }
 
          return -1;
      }
 
+     if (bootoncelabel[0] == 0) {
+         prom_get_options("boot-once", bootoncelabel, 
+                          sizeof(bootoncelabel));
+         if (bootoncelabel[0] != 0)
+               DEBUG_F("boot-once: [%s]\n", bootoncelabel);
+     }
+     prom_set_options("boot-once", NULL, 0);
+
      if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
          prom_printf("%s: Unable to parse\n", bootdevice);
          return -1;
      if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
          prom_printf("%s: Unable to parse\n", bootdevice);
          return -1;
@@ -1616,27 +1729,34 @@ yaboot_main(void)
      DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
             boot.dev, boot.part, boot.file);
 
      DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
             boot.dev, boot.part, boot.file);
 
-     if (strlen(boot.file)) {
-         if (!strncmp(boot.file, "\\\\", 2))
-              boot.file = "\\\\";
-         else {
-              char *p, *last;
-              p = last = boot.file;
-              while(*p) {
-                   if (*p == '\\')
-                        last = p;
-                   p++;
-              }
-              if (p)
-                   *(last) = 0;
-              else
-                   boot.file = "";
-              if (strlen(boot.file))
-                   strcat(boot.file, "\\");
-         }
+     if (!conf_given) {
+         if (_machine == _MACH_chrp)
+             boot.file = "/etc/";
+         else if (strlen(boot.file)) {
+             if (!strncmp(boot.file, "\\\\", 2))
+                 boot.file = "\\\\";
+             else {
+                 char *p, *last;
+                 p = last = boot.file;
+                 while(*p) {
+                     if (*p == '\\')
+                         last = p;
+                     p++;
+                 }
+                 if (p)
+                     *(last) = 0;
+                 else
+                     boot.file = "";
+                 if (strlen(boot.file))
+                     strcat(boot.file, "\\");
+             }
+         }
+         strcpy(conf_path, boot.file);
+         strcat(conf_path, CONFIG_FILE_NAME);
+         boot.file = conf_path;
+         DEBUG_F("After path kludgeup: dev=%s, part=%d, file=%s\n",
+            boot.dev, boot.part, boot.file);
      }
      }
-     DEBUG_F("After pmac path kludgeup: dev=%s, part=%d, file=%s\n",
-            boot.dev, boot.part, boot.file);
 
      /*
       * If we're doing a netboot, first look for one which matches our
 
      /*
       * If we're doing a netboot, first look for one which matches our