Author: mmel
Date: Sat Mar 26 06:59:01 2016
New Revision: 297286
URL: https://svnweb.freebsd.org/changeset/base/297286

Log:
  ARM: Parse command line delivered by U-Boot:
  - in atags
  - in DT blob (by using 'fdt chosen' U-Boot command)
  
  The command line must start with guard's string 'FreeBSD:' and can contain
  list of comma separated kenv strings. Also, boot modifier strings from
  boot.h are recognised and parsed into boothowto.
  
  The command line must be passed from U-Boot by setting of bootargs variable:
  'setenv bootargs FreeBSD:boot_single=1,vfs.root.mountfrom=ufs:/dev/ada0s1a'
  followed by 'fdt chosen' (only for DT based boot)

Modified:
  head/sys/arm/arm/machdep.c
  head/sys/dev/fdt/fdt_common.c
  head/sys/dev/fdt/fdt_common.h

Modified: head/sys/arm/arm/machdep.c
==============================================================================
--- head/sys/arm/arm/machdep.c  Sat Mar 26 06:57:36 2016        (r297285)
+++ head/sys/arm/arm/machdep.c  Sat Mar 26 06:59:01 2016        (r297286)
@@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/bus.h>
 #include <sys/cons.h>
 #include <sys/cpu.h>
+#include <sys/ctype.h>
 #include <sys/efi.h>
 #include <sys/exec.h>
 #include <sys/imgact.h>
@@ -74,6 +75,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/pcpu.h>
 #include <sys/ptrace.h>
 #include <sys/reboot.h>
+#include <sys/boot.h>
 #include <sys/rwlock.h>
 #include <sys/sched.h>
 #include <sys/signalvar.h>
@@ -232,6 +234,7 @@ static struct pv_addr kernelstack;
 #if defined(LINUX_BOOT_ABI)
 #define LBABI_MAX_BANKS        10
 
+#define CMDLINE_GUARD "FreeBSD:"
 uint32_t board_id;
 struct arm_lbabi_tag *atag_list;
 char linux_command_line[LBABI_MAX_COMMAND_LINE + 1];
@@ -1029,6 +1032,53 @@ pcpu0_init(void)
 }
 
 #if defined(LINUX_BOOT_ABI)
+
+/* Convert the U-Boot command line into FreeBSD kenv and boot options. */
+static void
+cmdline_set_env(char *cmdline, const char *guard)
+{
+       char *cmdline_next, *env;
+       size_t size, guard_len;
+       int i;
+
+       size = strlen(cmdline);
+       /* Skip leading spaces. */
+       for (; isspace(*cmdline) && (size > 0); cmdline++)
+               size--;
+
+       /* Test and remove guard. */
+       if (guard != NULL && guard[0] != '\0') {
+               guard_len  =  strlen(guard);
+               if (strncasecmp(cmdline, guard, guard_len) != 0){
+                       init_static_kenv(cmdline, 0);
+                       return;
+
+                       cmdline += guard_len;
+                       size -= guard_len;
+               }
+       }
+
+       /* Skip leading spaces. */
+       for (; isspace(*cmdline) && (size > 0); cmdline++)
+               size--;
+
+       /* Replace ',' with '\0'. */
+       /* TODO: implement escaping for ',' character. */
+       cmdline_next = cmdline;
+       while(strsep(&cmdline_next, ",") != NULL)
+               ;
+       init_static_kenv(cmdline, 0);
+       /* Parse boothowto. */
+       for (i = 0; howto_names[i].ev != NULL; i++) {
+               env = kern_getenv(howto_names[i].ev);
+               if (env != NULL) {
+                       if (strtoul(env, NULL, 10) != 0)
+                               boothowto |= howto_names[i].mask;
+                       freeenv(env);
+               }
+       }
+}
+
 vm_offset_t
 linux_parse_boot_param(struct arm_boot_params *abp)
 {
@@ -1036,6 +1086,7 @@ linux_parse_boot_param(struct arm_boot_p
        uint32_t revision;
        uint64_t serial;
        int size;
+       vm_offset_t lastaddr;
 #ifdef FDT
        struct fdt_header *dtb_ptr;
        uint32_t dtb_size;
@@ -1057,9 +1108,6 @@ linux_parse_boot_param(struct arm_boot_p
                return (fake_preload_metadata(abp, dtb_ptr, dtb_size));
        }
 #endif
-       /* Old, ATAG based boot must have board type set. */
-       if (abp->abp_r1 == 0)
-               return (0);
 
        board_id = abp->abp_r1;
        walker = (struct arm_lbabi_tag *)abp->abp_r2;
@@ -1089,10 +1137,9 @@ linux_parse_boot_param(struct arm_boot_p
                        board_set_revision(revision);
                        break;
                case ATAG_CMDLINE:
-                       /* XXX open question: Parse this for boothowto? */
                        size = ATAG_SIZE(walker) -
                            sizeof(struct arm_lbabi_header);
-                       size = min(size, sizeof(linux_command_line) - 1);
+                       size = min(size, LBABI_MAX_COMMAND_LINE);
                        strncpy(linux_command_line, walker->u.tag_cmd.command,
                            size);
                        linux_command_line[size] = '\0';
@@ -1107,9 +1154,9 @@ linux_parse_boot_param(struct arm_boot_p
        bcopy(atag_list, atags,
            (char *)walker - (char *)atag_list + ATAG_SIZE(walker));
 
-       init_static_kenv(NULL, 0);
-
-       return fake_preload_metadata(abp, NULL, 0);
+       lastaddr = fake_preload_metadata(abp, NULL, 0);
+       cmdline_set_env(linux_command_line, CMDLINE_GUARD);
+       return lastaddr;
 }
 #endif
 
@@ -1785,6 +1832,12 @@ initarm(struct arm_boot_params *abp)
        if (OF_init((void *)dtbp) != 0)
                panic("OF_init failed with the found device tree");
 
+#if defined(LINUX_BOOT_ABI)
+       if (fdt_get_chosen_bootargs(linux_command_line,
+           LBABI_MAX_COMMAND_LINE) == 0)
+               cmdline_set_env(linux_command_line, CMDLINE_GUARD);
+#endif
+
 #ifdef EFI
        efihdr = (struct efi_map_header *)preload_search_info(kmdp,
            MODINFO_METADATA | MODINFOMD_EFI_MAP);

Modified: head/sys/dev/fdt/fdt_common.c
==============================================================================
--- head/sys/dev/fdt/fdt_common.c       Sat Mar 26 06:57:36 2016        
(r297285)
+++ head/sys/dev/fdt/fdt_common.c       Sat Mar 26 06:59:01 2016        
(r297286)
@@ -722,3 +722,16 @@ fdt_get_unit(device_t dev)
 
        return (strtol(name,NULL,0));
 }
+
+int
+fdt_get_chosen_bootargs(char *bootargs, size_t max_size)
+{
+       phandle_t chosen;
+
+       chosen = OF_finddevice("/chosen");
+       if (chosen == -1)
+               return (ENXIO);
+       if (OF_getprop(chosen, "bootargs", bootargs, max_size) == -1)
+               return (ENXIO);
+       return (0);
+}
\ No newline at end of file

Modified: head/sys/dev/fdt/fdt_common.h
==============================================================================
--- head/sys/dev/fdt/fdt_common.h       Sat Mar 26 06:57:36 2016        
(r297285)
+++ head/sys/dev/fdt/fdt_common.h       Sat Mar 26 06:59:01 2016        
(r297286)
@@ -100,5 +100,6 @@ int fdt_parent_addr_cells(phandle_t);
 int fdt_reg_to_rl(phandle_t, struct resource_list *);
 int fdt_pm(phandle_t);
 int fdt_get_unit(device_t);
+int fdt_get_chosen_bootargs(char *bootargs, size_t max_size);
 
 #endif /* _FDT_COMMON_H_ */
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to