diff --git a/Documentation/boards/mvebu.rst b/Documentation/boards/mvebu.rst index b4f8e60..8e56122 100644 --- a/Documentation/boards/mvebu.rst +++ b/Documentation/boards/mvebu.rst @@ -28,14 +28,18 @@ Booting second stage -------------------- -This is currently not possible because barebox assumes the registers are mapped -at 0xd0000000 as is the case when the boot ROM gives control to the bootloader. +Since ``v2017.04.0`` barebox can boot a barebox image even if the register +window is moved. This is implemented by writing the actual window position +into the image where it is then picked up by the second stage bootloader. Booting from UART ----------------- The mvebu SoCs support booting from UART. For this there is a tool available in -barebox called kwboot. +barebox called ``kwboot``. Quite some mvebu boards are reset once more when +they already started to read the first block of the image to boot. If you want +to boot such a board, use the parameter ``-n 15`` for ``kwboot``. (The number +might have to be adapted per board.) mvebu boards ------------ diff --git a/Documentation/boards/mvebu/Netgear-ReadyNAS-2120.rst b/Documentation/boards/mvebu/Netgear-ReadyNAS-2120.rst index 5bee03a..488af2d 100644 --- a/Documentation/boards/mvebu/Netgear-ReadyNAS-2120.rst +++ b/Documentation/boards/mvebu/Netgear-ReadyNAS-2120.rst @@ -6,14 +6,5 @@ UART booting ------------ -The first UART hides behind a sticker on 4 pins. - -The machine seems to do two resets at power on which makes UART booting hard. A -trick to work around this is:: - - scripts/kwboot -d /dev/ttyUSB0; kwboot -b images/barebox-netgear-rn2120.img -t /dev/ttyUSB0 - -This way the first window in which the CPU accepts the magic string is taken by -the first invokation which blocks until the second reset happens. The second -window is then hit with the image to boot. This is not 100% reliable but works -most of the time. +The UART that can be used to boot via RS232 (using ``kwboot``) hides behind a +sticker on the backside of the machine. It uses TTL levels. diff --git a/Documentation/devicetree/bindings/firmware/altr,passive-serial.txt b/Documentation/devicetree/bindings/firmware/altr,passive-serial.txt index d357dd3..eec12fb 100644 --- a/Documentation/devicetree/bindings/firmware/altr,passive-serial.txt +++ b/Documentation/devicetree/bindings/firmware/altr,passive-serial.txt @@ -6,7 +6,8 @@ to start the FPGA. Required properties: -- compatible: shall be "altr,fpga-passive-serial" +- compatible: shall be "altr,fpga-passive-serial" or + "altr,fpga-arria10-passive-serial" for Arria 10 - reg: SPI chip select - nstat-gpios: Specify GPIO for controlling the nstat pin - confd-gpios: Specify GPIO for controlling the confd pin diff --git a/Documentation/user/booting-linux.rst b/Documentation/user/booting-linux.rst index f26299e..66f64ec 100644 --- a/Documentation/user/booting-linux.rst +++ b/Documentation/user/booting-linux.rst @@ -229,10 +229,10 @@ Network boot ------------ -With the following steps barebox can start the Kernel and root filesystem -over network, a standard development case. +With the following steps, barebox can start the kernel and root filesystem +over the network, a standard development case. -Configure network: edit ``/env/network/eth0``. For a standard dhcp setup +Configure network: edit ``/env/network/eth0``. For a standard DHCP setup the following is enough: .. code-block:: sh @@ -242,8 +242,11 @@ ip=dhcp serverip=192.168.23.45 -serverip is only necessary if it differs from the serverip offered from the dhcp server. -A static ip setup can look like this: +The optional setting ``serverip`` specifies the IP address of your TFTP and NFS +server, and is only necessary if it differs from the server IP offered by the +DHCP server (i.e., the field ``siaddr`` in the DHCP ACK Reply). + +A static IP setup can look like this: .. code-block:: sh @@ -255,27 +258,43 @@ gateway=192.168.2.1 serverip=192.168.2.1 -Note that barebox will pass the same ip settings to the kernel, i.e. it passes -``ip=$ipaddr:$serverip:$gateway:$netmask::eth0:`` for a static ip setup and -``ip=dhcp`` for a dynamic dhcp setup. +Note that barebox will pass the same IP settings to the kernel, i.e. it passes +``ip=$ipaddr:$serverip:$gateway:$netmask::eth0:`` for a static IP setup and +``ip=dhcp`` for a dynamic DHCP setup. -Adjust ``global.user`` and maybe ``global.hostname`` in ``/env/config``:: +By default, barebox uses the variables ``global.user`` and ``global.hostname`` +to retrieve its kernel image over TFTP, which makes it possible to use multiple +boards for multiple users with one single server. +You can adjust those variables in ``/env/config``:: global.user=sha global.hostname=efikasb -Copy the kernel (and devicetree if needed) to the base dir of the TFTP server:: +Copy the kernel (and devicetree if needed) to the root directory of your TFTP +server, and name them accordingly; for example:: cp zImage /tftpboot/sha-linux-efikasb cp myboard.dtb /tftpboot/sha-oftree-efikasb -barebox will pass ``nfsroot=/home/${global.user}/nfsroot/${global.hostname}`` -This may be a link to another location on the NFS server. Make sure that the -link target is exported from the server. +(In this example, the directory ``/tftpboot`` represents the root directory of +the TFTP server. +That directory depends on the configuration of your TFTP server, some servers +may also use ``/srv/tftp`` instead.) -``boot net`` will then start the Kernel. +barebox will pass ``nfsroot=/home/${global.user}/nfsroot/${global.hostname}`` to +the kernel. +This causes the kernel to mount its root filesystem from a NFS server, which is +detected through the DHCP reply. +To choose a different server, simply prepend its IP address to the mount path, +e.g. ``nfsroot=192.168.23.5:/home/...``. +In any case, make sure that the specified mountpoint is exported by your NFS +server. -If the paths or names are not suitable they can be adjusted in +For more information about booting with ``nfsroot``, see +`Documentation/filesystems/nfs/nfsroot.txt `__ +in the Linux kernel documentation. + +If the preconfigured paths or names are not suitable, they can be adjusted in ``/env/boot/net``: .. code-block:: sh @@ -294,3 +313,6 @@ nfsroot="/home/${global.user}/nfsroot/${global.hostname}" bootargs-ip global.linux.bootargs.dyn.root="root=/dev/nfs nfsroot=$nfsroot,v3,tcp" + +``boot net`` will then retrieve the kernel (and also the device tree and +initramfs, if used) over TFTP and boot it. diff --git a/Documentation/user/random.rst b/Documentation/user/random.rst new file mode 100644 index 0000000..95dad72 --- /dev/null +++ b/Documentation/user/random.rst @@ -0,0 +1,63 @@ +Random Number Generator support +=============================== + +Barebox provides two types of RNG sources - PRNG and HWRNG: + +- "A pseudorandom number generator (PRNG), also known as a deterministic random + bit generator (DRBG),[1] is an algorithm for generating a sequence of numbers + whose properties approximate the properties of sequences of random numbers. + The PRNG-generated sequence is not truly random, because it is completely + determined by a relatively small set of initial values, called the PRNG's seed + (which may include truly random values). Although sequences that are closer to + truly random can be generated using hardware random number generators." + Pseudorandom number generator. https://en.wikipedia.org/wiki/Pseudorandom_number_generator (2017.05.08). + The PRNG used by Barebox is LCG (linear congruential generator) non cryptographically + secure, so please use with caution. + +- The HWRNG framework is software that makes use of a special hardware feature on + your CPU, SoC or motherboard. It can‘t provide any guarantee about cryptographic + security of used HW. Please refer to vendor documentation and/or RNG certification. + +API +^^^ + +.. code-block:: c + + /* seed the PRNG. */ + void srand(unsigned int seed); + + /* Fill the buffer with PRNG bits. */ + void get_random_bytes(void *buf, int len); + + /* Fill the buffer with bits provided by HWRNG. + * This function may fail with a message “error: no HWRNG available!” + * in case HWRNG is not available or HW got some runtime error. + * If barebox is compiled with CONFIG_ALLOW_PRNG_FALLBACK, + * then get_crypto_bytes() will print “warning: falling back to Pseudo RNG source!” + * and use PRNG instead of returning error. + */ + int get_crypto_bytes(void *buf, int len); + +User interface +^^^^^^^^^^^^^^ + +- /dev/hwrng0 + provides access to first available HWRNG. To examine this source you can use: + +.. code-block:: sh + + md -s /dev/hwrng0 + +- /dev/prng + provides access to PRNG. To examine this source you can use: + +.. code-block:: sh + + md -s /dev/prng + +To seed PRNG from user space the :ref:`command_seed` is provided. For example: + +.. code-block:: sh + + seed 12345 + md -s /dev/prng diff --git a/Documentation/user/usb.rst b/Documentation/user/usb.rst index bbcb045..ec219cf 100644 --- a/Documentation/user/usb.rst +++ b/Documentation/user/usb.rst @@ -216,3 +216,24 @@ musb-hdrc: setup fifo_mode 4 musb-hdrc: 28/31 max ep, 16384/16384 memory barebox:/ + +USB Gadget autostart Support +---------------------------- + +Barebox can be configured to start usbgadget automatically by using global variables, +instead of creating boot script. This can be useful if autostart policy should be +chosen at boot time from other driver or script. +To get usbgadget autostart support barebox has to be compiled with +CONFIG_USB_GADGET_AUTOSTART enabled. + +USB Gadget autostart Options +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``global.usbgadget.autostart`` + Boolean flag. If set to 1, usbgadget will be started automatically on boot and + enable USB OTG mode. (Default 0). +``global.usbgadget.acm`` + Boolean flag. If set to 1, CDC ACM function will be created. + See :ref:`command_usbgadget` -a. (Default 0). +``global.usbgadget.fastboot_function`` + Function description for fastboot. See :ref:`command_usbgadget` -A [desc]. diff --git a/Documentation/user/user-manual.rst b/Documentation/user/user-manual.rst index 435649f..791c8e0 100644 --- a/Documentation/user/user-manual.rst +++ b/Documentation/user/user-manual.rst @@ -33,6 +33,7 @@ reset-reason system-reset state + random * :ref:`search` * :ref:`genindex` diff --git a/commands/edit.c b/commands/edit.c index 696a818..290222c 100644 --- a/commands/edit.c +++ b/commands/edit.c @@ -559,7 +559,7 @@ return ret; } -static const char *edit_aliases[] = { "sedit", NULL}; +static const char * const edit_aliases[] = { "sedit", NULL}; BAREBOX_CMD_HELP_START(edit) BAREBOX_CMD_HELP_TEXT("Use cursor keys, Ctrl-C to exit and Ctrl-D to exit-with-save.") diff --git a/commands/help.c b/commands/help.c index 819c406..34ffa9a 100644 --- a/commands/help.c +++ b/commands/help.c @@ -139,7 +139,7 @@ BAREBOX_CMD_HELP_OPT ("-v", "verbose") BAREBOX_CMD_HELP_END -static const char *help_aliases[] = { "?", NULL}; +static const char * const help_aliases[] = { "?", NULL}; BAREBOX_CMD_START(help) .cmd = do_help, diff --git a/commands/mount.c b/commands/mount.c index aa769d4..4cf1179 100644 --- a/commands/mount.c +++ b/commands/mount.c @@ -29,7 +29,7 @@ int opt, verbose = 0; struct driver_d *drv; const char *type = NULL; - const char *mountpoint, *dev; + const char *mountpoint, *devstr; const char *fsoptions = NULL; while ((opt = getopt(argc, argv, "ao:t:v")) > 0) { @@ -70,11 +70,11 @@ return 0; } + devstr = argv[optind]; + if (argc == optind + 1) { struct cdev *cdev; - const char *path, *devstr; - - devstr = argv[optind]; + const char *path; if (!strncmp(devstr, "/dev/", 5)) devstr += 5; @@ -97,8 +97,6 @@ if (argc < optind + 2) return COMMAND_ERROR_USAGE; - dev = argv[optind]; - if (argc == optind + 3) { /* * Old behaviour: mount @@ -109,7 +107,7 @@ mountpoint = argv[optind + 1]; } - return mount(dev, type, mountpoint, fsoptions); + return mount(devstr, type, mountpoint, fsoptions); } BAREBOX_CMD_HELP_START(mount) @@ -119,6 +117,7 @@ BAREBOX_CMD_HELP_TEXT("can be detected automatically to /mnt/PARTNAME") BAREBOX_CMD_HELP_TEXT("If mountpoint is not given, a standard mountpoint of /mnt/DEVICE") BAREBOX_CMD_HELP_TEXT("is used. This directoy is created automatically if necessary.") +BAREBOX_CMD_HELP_TEXT("With -o loop the mount command mounts a file instead of a device.") BAREBOX_CMD_HELP_TEXT("") BAREBOX_CMD_HELP_TEXT("Options:") BAREBOX_CMD_HELP_OPT("-a\t", "mount all blockdevices") diff --git a/commands/test.c b/commands/test.c index d0f63c1..c4f4938 100644 --- a/commands/test.c +++ b/commands/test.c @@ -224,7 +224,7 @@ return expr; } -static const char *test_aliases[] = { "[", NULL}; +static const char * const test_aliases[] = { "[", NULL}; BAREBOX_CMD_HELP_START(test) BAREBOX_CMD_HELP_TEXT("Options:") diff --git a/commands/true.c b/commands/true.c index 24dea46..ad2be8e 100644 --- a/commands/true.c +++ b/commands/true.c @@ -26,7 +26,10 @@ return 0; } +static const char * const true_aliases[] = { ":", NULL}; + BAREBOX_CMD_START(true) + .aliases = true_aliases, .cmd = do_true, BAREBOX_CMD_DESC("do nothing, successfully") BAREBOX_CMD_GROUP(CMD_GRP_SCRIPT) diff --git a/commands/usbgadget.c b/commands/usbgadget.c index 02c2c96..ba09f97 100644 --- a/commands/usbgadget.c +++ b/commands/usbgadget.c @@ -106,7 +106,8 @@ BAREBOX_CMD_HELP_TEXT("Options:") BAREBOX_CMD_HELP_OPT ("-a", "Create CDC ACM function") BAREBOX_CMD_HELP_OPT ("-s", "Create Generic Serial function") -BAREBOX_CMD_HELP_OPT ("-A ", "Create Android Fastboot function") +BAREBOX_CMD_HELP_OPT ("-A [desc]", "Create Android Fastboot function. If 'desc' is not provided,") +BAREBOX_CMD_HELP_OPT ("", "trying to use 'global.usbgadget.fastboot_function' variable.") BAREBOX_CMD_HELP_OPT ("-D ", "Create DFU function") BAREBOX_CMD_HELP_OPT ("-d", "Disable the currently running gadget") BAREBOX_CMD_HELP_END diff --git a/common/block.c b/common/block.c index 0edc861..e2ba9d4 100644 --- a/common/block.c +++ b/common/block.c @@ -374,6 +374,8 @@ list_add_tail(&blk->list, &block_device_list); + cdev_create_default_automount(&blk->cdev); + return 0; } diff --git a/common/command.c b/common/command.c index 03c7083..d9cc4a6 100644 --- a/common/command.c +++ b/common/command.c @@ -104,7 +104,7 @@ list_add_sort(&cmd->list, &command_list, compare); if (cmd->aliases) { - char **aliases = (char**)cmd->aliases; + const char * const *aliases = cmd->aliases; while(*aliases) { struct command *c = xzalloc(sizeof(struct command)); diff --git a/common/hush.c b/common/hush.c index d3f7bf3..792b61a 100644 --- a/common/hush.c +++ b/common/hush.c @@ -1974,7 +1974,7 @@ return ret; } -static const char *source_aliases[] = { ".", NULL}; +static const char * const source_aliases[] = { ".", NULL}; BAREBOX_CMD_HELP_START(source) BAREBOX_CMD_HELP_TEXT("Read and execute commands from FILE in the current shell environment.") diff --git a/drivers/firmware/altera_serial.c b/drivers/firmware/altera_serial.c index b119778..3a0175d 100644 --- a/drivers/firmware/altera_serial.c +++ b/drivers/firmware/altera_serial.c @@ -25,11 +25,12 @@ #include #include - /* * Physical requirements: - * - three free GPIOs for the signals nCONFIG, CONFIGURE_DONE, nSTATUS - * - 32 bit per word, LSB first capable SPI master (MOSI + clock) + * - free GPIOs for the signals nCONFIG, CONFIGURE_DONE, nSTATUS (optionally + * for ARRIA 10) + * - 32 bit / 8 bit (ARRIA 10) per word, LSB first capable SPI master + * (MOSI + clock) * * Example how to configure this driver via device tree * @@ -43,6 +44,13 @@ * }; */ +struct altera_ps_data { + int status_wait_max_us; + int t_st2ck_us; + int spi_bits_per_word; + int padding; +}; + struct fpga_spi { struct firmware_handler fh; int nstat_gpio; /* input GPIO to read the status line */ @@ -50,9 +58,36 @@ int nconfig_gpio; /* output GPIO to start the FPGA's config */ struct device_d *dev; struct spi_device *spi; + const struct altera_ps_data *data; bool padding_done; }; +/* | Arria 5 | Arria 10 | + * t_CF2ST0 | [; 600] | [; 600] | ns + * t_CFG | [2;] | [2;] | µs + * t_STATUS | [268; 1506] | [268; 3000] | µs + * t_CF2ST1 | [; 1506] | [; 3000] | µs + * t_CF2CK | [1506;] | [3010 µs;] | µs + * t_ST2CK | [2;] | [10;] | µs + * t_CD2UM | [175; 437] | [175; 830] | µs + */ + +/* Arria 5 */ +static struct altera_ps_data a5_data = { + .status_wait_max_us = 1506, /* max(t_CF2ST1) */ + .t_st2ck_us = 2, /* min(t_ST2CK) */ + .spi_bits_per_word = 32, + .padding = true, +}; + +/* Arria 10 */ +static struct altera_ps_data a10_data = { + .status_wait_max_us = 3000, /* max(t_CF2ST1) */ + .t_st2ck_us = 10, /* min(t_ST2CK) */ + .spi_bits_per_word = 8, + .padding = false, +}; + static int altera_spi_open(struct firmware_handler *fh) { struct fpga_spi *this = container_of(fh, struct fpga_spi, fh); @@ -77,7 +112,6 @@ (gpio_get_value(this->confd_gpio) == 0)); } - if (ret != 0) { dev_err(dev, "FPGA does not acknowledge the programming initiation\n"); if (gpio_is_valid(this->nstat_gpio) && gpio_get_value(this->nstat_gpio)) @@ -94,24 +128,30 @@ this->padding_done = false; /* - * after about 1506 µs the FPGA must acknowledge this step - * with the STATUS line at high level + * after max { max(t_STATUS), max(t_CF2ST1) } the FPGA must acknowledge this + * step with the STATUS line at high level */ - if (gpio_is_valid(this->nstat_gpio)) { - ret = wait_on_timeout(1600 * USECOND, - gpio_get_value(this->nstat_gpio) == 1); - if (ret != 0) { - dev_err(dev, "FPGA does not acknowledge the programming start\n"); + ret = wait_on_timeout(this->data->status_wait_max_us * USECOND, + gpio_get_value(this->nstat_gpio)); + if (ret) { + dev_err(dev, "nSTATUS still low after max(t_CF2ST1)! %d\n", ret); return ret; } } else { - udelay(1600); + udelay(this->data->status_wait_max_us); } dev_dbg(dev, "Initiating passed\n"); - /* at the end, wait at least 2 µs prior beginning writing data */ - udelay(2); + + /* + * t_CF2CK doesn't need to be honored if nSTATUS is monitored in which + * case only t_ST2CK applies. As we have + * max(t_CF2ST1) + min(t_ST2CK) >= min(t_CF2CK) + * and we waited for max(t_CF2ST1) in the non-monitored + * case already above, only waiting for min(t_ST2CK) is fine here. + */ + udelay(this->data->t_st2ck_us * USECOND); return 0; } @@ -129,30 +169,38 @@ spi_message_init(&m); - if (sz < sizeof(u32)) { - /* simple padding */ - dummy = 0; - memcpy(&dummy, buf, sz); - buf = &dummy; - sz = sizeof(u32); - this->padding_done = true; - } + if (this->data->padding) { + if (sz < sizeof(u32)) { + /* simple padding */ + dummy = 0; + memcpy(&dummy, buf, sz); + buf = &dummy; + sz = sizeof(u32); + this->padding_done = true; + } - t[0].tx_buf = buf; - t[0].rx_buf = NULL; - t[0].len = sz; - spi_message_add_tail(&t[0], &m); + t[0].tx_buf = buf; + t[0].rx_buf = NULL; + t[0].len = sz; + spi_message_add_tail(&t[0], &m); - if (sz & 0x3) { /* padding required? */ - u32 *word_buf = (u32 *)buf; - dummy = 0; - memcpy(&dummy, &word_buf[sz >> 2], sz & 0x3); - t[0].len &= ~0x03; - t[1].tx_buf = &dummy; - t[1].rx_buf = NULL; - t[1].len = sizeof(u32); - spi_message_add_tail(&t[1], &m); - this->padding_done = true; + if (sz & 0x3) { /* padding required? */ + u32 *word_buf = (u32 *)buf; + dummy = 0; + memcpy(&dummy, &word_buf[sz >> 2], sz & 0x3); + t[0].len &= ~0x03; + t[1].tx_buf = &dummy; + t[1].rx_buf = NULL; + t[1].len = sizeof(u32); + spi_message_add_tail(&t[1], &m); + this->padding_done = true; + } + } else { + memset(&t[0], 0, sizeof(t[0])); + t[0].tx_buf = buf; + t[0].rx_buf = NULL; + t[0].len = sz; + spi_message_add_tail(&t[0], &m); } ret = spi_sync(this->spi, &m); @@ -173,7 +221,7 @@ dev_dbg(dev, "Finalize programming\n"); - if (this->padding_done == false) { + if (this->data->padding && this->padding_done == false) { spi_message_init(&m); t.tx_buf = &dummy; t.rx_buf = NULL; @@ -196,12 +244,23 @@ } else { ret = wait_on_timeout(10 * USECOND, (gpio_get_value(this->confd_gpio) == 1)); - } + if (ret == 0) { dev_dbg(dev, "Programming successful\n"); - return ret; + + /* + * After CONF_DONE goes high, send two additional falling edges on DCLK + * to begin initialization and enter user mode + */ + spi_message_init(&m); + memset(&t, 0, sizeof(t)); + t.tx_buf = NULL; + t.rx_buf = NULL; + t.len = 2; + spi_message_add_tail(&t, &m); + return spi_sync(this->spi, &m); } dev_err(dev, "Programming failed due to time out\n"); @@ -267,9 +326,10 @@ return ret; } -static void altera_spi_init_mode(struct spi_device *spi) +static void altera_spi_init_mode(struct spi_device *spi, int spi_bits_per_word) { - spi->bits_per_word = 32; + spi->bits_per_word = spi_bits_per_word; + /* * CPHA = CPOL = 0 * the FPGA expects its firmware data with LSB first @@ -284,9 +344,14 @@ struct firmware_handler *fh; const char *alias = of_alias_get(dev->device_node); const char *model = NULL; + const struct altera_ps_data *data; dev_dbg(dev, "Probing FPGA firmware programmer\n"); + rc = dev_get_drvdata(dev, (const void **)&data); + if (rc) + return rc; + this = xzalloc(sizeof(*this)); fh = &this->fh; @@ -308,7 +373,9 @@ fh->dev = dev; this->spi = (struct spi_device *)dev->type_data; - altera_spi_init_mode(this->spi); + this->data = data; + + altera_spi_init_mode(this->spi, this->data->spi_bits_per_word); this->dev = dev; dev_dbg(dev, "Registering FPGA firmware programmer\n"); @@ -327,9 +394,9 @@ } static struct of_device_id altera_spi_id_table[] = { - { - .compatible = "altr,fpga-passive-serial", - }, + { .compatible = "altr,fpga-passive-serial", .data = &a5_data }, + { .compatible = "altr,fpga-arria10-passive-serial", .data = &a10_data }, + { } }; static struct driver_d altera_spi_driver = { diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index caece3b..fd1665b 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -281,7 +281,7 @@ if (drv_data->bytes_left == 1) drv_data->cntl_bits &= ~REG_CONTROL_ACK; - udelay(2); + udelay(2); break; case STATUS_MAST_RD_DATA_NO_ACK: /* 0x58 */ diff --git a/drivers/of/base.c b/drivers/of/base.c index c9bdd91..33f6162 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1910,6 +1910,8 @@ barebox_set_model(of_model); memory = of_find_node_by_path("/memory"); + if (!memory) + memory = of_find_node_by_type(root_node, "memory"); if (memory) of_add_memory(memory, false); diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c index 83d8045..4a2d34f 100644 --- a/drivers/rtc/rtc-lib.c +++ b/drivers/rtc/rtc-lib.c @@ -20,13 +20,6 @@ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; -static const unsigned short rtc_ydays[2][13] = { - /* Normal years */ - { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, - /* Leap years */ - { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } -}; - #define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400) /* diff --git a/fs/devfs-core.c b/fs/devfs-core.c index 382606f..3368d3e 100644 --- a/fs/devfs-core.c +++ b/fs/devfs-core.c @@ -20,11 +20,14 @@ #include #include #include +#include #include #include #include #include +#include #include +#include LIST_HEAD(cdev_list); @@ -332,6 +335,8 @@ devfs_create(new); + cdev_create_default_automount(new); + return new; } @@ -407,3 +412,90 @@ return 0; } + +struct loop_priv { + int fd; +}; + +static ssize_t loop_read(struct cdev *cdev, void *buf, size_t count, + loff_t offset, ulong flags) +{ + struct loop_priv *priv = cdev->priv; + loff_t ofs; + + ofs = lseek(priv->fd, offset, SEEK_SET); + if (ofs < 0) + return ofs; + + return read(priv->fd, buf, count); +} + +static ssize_t loop_write(struct cdev *cdev, const void *buf, size_t count, + loff_t offset, ulong flags) +{ + struct loop_priv *priv = cdev->priv; + loff_t ofs; + + ofs = lseek(priv->fd, offset, SEEK_SET); + if (ofs < 0) + return ofs; + + return write(priv->fd, buf, count); +} + +static const struct file_operations loop_ops = { + .read = loop_read, + .write = loop_write, + .memmap = generic_memmap_rw, + .lseek = dev_lseek_default, +}; + +struct cdev *cdev_create_loop(const char *path, ulong flags) +{ + struct cdev *new; + struct loop_priv *priv; + static int loopno; + loff_t ofs; + + priv = xzalloc(sizeof(*priv)); + + priv->fd = open(path, flags); + if (priv->fd < 0) { + free(priv); + return NULL; + } + + new = xzalloc(sizeof(*new)); + + new->ops = &loop_ops; + new->name = basprintf("loop%u", loopno++); + new->priv = priv; + + ofs = lseek(priv->fd, 0, SEEK_END); + if (ofs < 0) { + free(new); + free(priv); + return NULL; + } + lseek(priv->fd, 0, SEEK_SET); + + new->size = ofs; + new->offset = 0; + new->dev = NULL; + new->flags = 0; + + devfs_create(new); + + return new; +} + +void cdev_remove_loop(struct cdev *cdev) +{ + struct loop_priv *priv = cdev->priv; + + devfs_remove(cdev); + close(priv->fd); + free(priv); + free(cdev->name); + free(cdev); +} diff --git a/fs/fs.c b/fs/fs.c index 1da0805..0a5b61a 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -36,6 +36,8 @@ #include #include +#include "parseopt.h" + char *mkmodestr(unsigned long mode, char *str) { static const char *l = "xwr"; @@ -404,6 +406,20 @@ } EXPORT_SYMBOL(automount_add); +void cdev_create_default_automount(struct cdev *cdev) +{ + char *path, *cmd; + + path = basprintf("/mnt/%s", cdev->name); + cmd = basprintf("mount %s", cdev->name); + + make_directory(path); + automount_add(path, cmd); + + free(cmd); + free(path); +} + void automount_print(void) { struct automount *am; @@ -1193,6 +1209,9 @@ if (fsdev->cdev) cdev_close(fsdev->cdev); + if (fsdev->loop) + cdev_remove_loop(fsdev->cdev); + free(fsdev->backingstore); free(fsdev); } @@ -1219,13 +1238,18 @@ } EXPORT_SYMBOL(register_fs_driver); -static const char *detect_fs(const char *filename) +static const char *detect_fs(const char *filename, const char *fsoptions) { enum filetype type; struct driver_d *drv; struct fs_driver_d *fdrv; + bool loop; - type = cdev_detect_type(filename); + parseopt_b(fsoptions, "loop", &loop); + if (loop) + type = file_name_detect_type(filename); + else + type = cdev_detect_type(filename); if (type == filetype_unknown) return NULL; @@ -1242,7 +1266,11 @@ int fsdev_open_cdev(struct fs_device_d *fsdev) { - fsdev->cdev = cdev_open(fsdev->backingstore, O_RDWR); + parseopt_b(fsdev->options, "loop", &fsdev->loop); + if (fsdev->loop) + fsdev->cdev = cdev_create_loop(fsdev->backingstore, O_RDWR); + else + fsdev->cdev = cdev_open(fsdev->backingstore, O_RDWR); if (!fsdev->cdev) return -EINVAL; @@ -1295,7 +1323,7 @@ } if (!fsname) - fsname = detect_fs(device); + fsname = detect_fs(device, fsoptions); if (!fsname) return -ENOENT; diff --git a/fs/parseopt.c b/fs/parseopt.c index 12dbe18..8ff8301 100644 --- a/fs/parseopt.c +++ b/fs/parseopt.c @@ -2,6 +2,32 @@ #include "parseopt.h" +void parseopt_b(const char *options, const char *opt, bool *val) +{ + const char *start; + size_t optlen = strlen(opt); + +again: + start = strstr(options, opt); + + if (!start) { + *val = false; + return; + } + + if (start > options && start[-1] != ',') { + options = start; + goto again; + } + + if (start[optlen] != ',' && start[optlen] != '\0') { + options = start; + goto again; + } + + *val = true; +} + void parseopt_hu(const char *options, const char *opt, unsigned short *val) { const char *start; diff --git a/fs/parseopt.h b/fs/parseopt.h index a8523b6..abf3be3 100644 --- a/fs/parseopt.h +++ b/fs/parseopt.h @@ -1 +1,2 @@ +void parseopt_b(const char *options, const char *opt, bool *val); void parseopt_hu(const char *options, const char *opt, unsigned short *val); diff --git a/include/command.h b/include/command.h index 43ee454..0afc5c7 100644 --- a/include/command.h +++ b/include/command.h @@ -40,7 +40,7 @@ */ struct command { const char *name; /* Command Name */ - const char **aliases; + const char * const *aliases; /* Implementation function */ int (*cmd)(int, char *[]); int (*complete)(struct string_list *sl, char *instr); diff --git a/include/driver.h b/include/driver.h index 52e06f7..3d701f2 100644 --- a/include/driver.h +++ b/include/driver.h @@ -440,7 +440,7 @@ #define MAX_PARTUUID_STR sizeof("00112233-4455-6677-8899-AABBCCDDEEFF") struct cdev { - struct file_operations *ops; + const struct file_operations *ops; void *priv; struct device_d *dev; struct device_node *device_node; @@ -473,6 +473,8 @@ struct cdev *cdev_readlink(struct cdev *cdev); struct cdev *cdev_by_device_node(struct device_node *node); struct cdev *cdev_open(const char *name, unsigned long flags); +struct cdev *cdev_create_loop(const char *path, ulong flags); +void cdev_remove_loop(struct cdev *cdev); int cdev_do_open(struct cdev *, unsigned long flags); void cdev_close(struct cdev *cdev); int cdev_flush(struct cdev *cdev); @@ -490,6 +492,14 @@ loff_t size, unsigned int flags, const char *name); int devfs_del_partition(const char *name); +#ifdef CONFIG_FS_AUTOMOUNT +void cdev_create_default_automount(struct cdev *cdev); +#else +static inline void cdev_create_default_automount(struct cdev *cdev) +{ +} +#endif + #define DEVFS_PARTITION_APPEND 0 /** diff --git a/include/fs.h b/include/fs.h index 71edb22..d7fa771 100644 --- a/include/fs.h +++ b/include/fs.h @@ -92,6 +92,7 @@ struct fs_driver_d *driver; struct cdev *cdev; + bool loop; char *path; struct device_d *parent_device; struct list_head list; diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index e79998c..b084baca 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -448,3 +448,9 @@ $(obj)/%.bct: $(obj)/%.bct.cfg $(call cmd,cboot_bct) + +quiet_cmd_b64dec = B64DEC $@ + cmd_b64dec = base64 -d $< > $@ + +%: %.base64 + $(call cmd,b64dec)