From: Danny Milosavljevic <dannym@scratchpost.org>
To: David Craven <david@craven.ch>
Cc: guix-devel <guix-devel@gnu.org>
Subject: Guix with U-Boot
Date: Mon, 29 Aug 2016 12:31:49 +0200 [thread overview]
Message-ID: <20160829123149.0e260af6@scratchpost.org> (raw)
In-Reply-To: <CAL1_imn2JcqFo2TxM9jaQotUkR-fRQ9ncZqi8-QYv4qYiZB5og@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1373 bytes --]
Hi,
On Sun, 28 Aug 2016 14:28:31 +0200
David Craven <david@craven.ch> wrote:
> Thanks for your suggestions. I pushed the packages.
>
> Is there a git repo somewhere I can pull your uboot stuff from? I'd
> like to test it =)
There's no such repo right now.
I'd prefer merging into master soon to creating a fork.
For what it's worth, the changes I sent to the mailing list were tested on my machines, including that the Grub support still works.
If merging is deemed too risky, would it be possible to create a "wip-u-boot" branch on Savannah instead? - it seems that is how these bigger changes are handled. Then I could push the U-Boot parts there.
I've attached the UNFINISHED u-boot-install program which installs the U-Boot bootloader (comparable to grub-install). I plan to upstream it into the U-Boot main repository eventually. The other parts required for u-boot support were all already posted to our mailing list here.
gnu/packages/u-boot.scm could be merged now - it shouldn't affect anything because it's unused by master.
Other than that, it's mostly renaming "grub" -> "bootloader" in the Guix main source code that it creating a massive amount of noise in the patches I sent before. The actual functional change is a small part.
> I'm interested in starting a riscv port of guixsd at some point.
Nice! I think RISC-V is quite important to have.
[-- Attachment #2: u-boot-install.c --]
[-- Type: text/x-c++src, Size: 14678 bytes --]
/** u-boot-install.
SPDX GPLv3+
Installation methods are:
A20:
/proc/cpuinfo:
Processor : ARMv7 Processor rev 4 (v7l)
Hardware : sun7i "platform"; check the U-Boot config for this.
U-Boot [def]config:
CONFIG_ARCH_SUNXI=y
CONFIG_MACH_SUN7I=y
CONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-olinuxino-lime2"
Installer for Allwinner:
dd if=u-boot-sunxi-with-spl.bin of=/dev/sdX bs=1024 seek=8 ; can be done by parted. ped_device_write, ped_device_sync, ...
Novena:
"We ship a simple script called novena-install-spl. This simply does a dd of the file to the specified disk."
disk=/dev/disk/by-path/platform-2198000.usdhc
file=/boot/u-boot.spl
if ! dd if="${file}" of="${disk}" bs=1024 seek=1 conv=notrunc 2> /dev/null
Raspberry Pi:
mount /dev/sdb1 /mnt/tmp
cp u-boot.bin /mnt/tmp/kernel.img
umount /mnt/tmp
STMicroelectronics:
http://www.stlinux.com/u-boot/install [from the U-Boot prompt]
Sheevaplug:
http://www.cyrius.com/debian/kirkwood/sheevaplug/uboot-upgrade/
Xilinx:
Downloading U-Boot to MicroBlaze
http://www.wiki.xilinx.com/Build+U-Boot */
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <parted/parted.h>
#include <sys/types.h>
#include <sys/stat.h>
/** skip_overlay_long_line: given a FILE, skips forward until the next '\n'. It also skips the '\n'.
* @param f File to read */
static void skip_overly_long_line(FILE* f) {
char buf[200];
/* skip overly long lines */
while (fgets(buf, sizeof(buf), f) != NULL && strchr(buf, '\n') == NULL)
;
}
/** read_value_of_key_value_file: Read the value of a <key>=<value> file with the given key and return it.
* @param separator separator between key and value
* @param filename of file to read. File will be opened and closed automatically.
* @param key key to search for. Whitespace after key in file is ignored.
* @param value buffer to store value in. Will be NUL terminated if result != NULL.
* @param valuesize size of buffer, including the NUL terminator.
* @return value if successful, NULL otherwise.
*
* Cannot return values from lines which are longer than 399 Byte.
*/
static const char* read_value_of_key_value_file(char separator, const char* filename, const char* key, char* value, size_t valuesize) {
char buf[400];
char* result = NULL;
FILE* f = fopen(filename, "r");
if (f == NULL)
return NULL;
while (fgets(buf, sizeof(buf), f) != NULL) {
if (strchr(buf, '\n') == NULL) {
fprintf(stderr, "Warning: skipping overly long line that starts with \"%s\".\n", buf);
skip_overly_long_line(f);
} else {
const char* xkey = buf;
char* sep = strchr(buf, separator);
if (sep != NULL) { /* we have key and value */
*sep = 0; /* just in case separator is ' ' */
const char* xvalue = sep + 1;
/* strip leading whitespace from xvalue */
while (*xvalue == ' ' || *xvalue == '\t')
++xvalue;
/* strip trailing whitespace from key */
for (--sep; sep >= xkey; --sep) {
if (*sep != ' ' && *sep != '\t')
break;
*sep = 0;
}
if (strcmp(key, xkey) == 0 && valuesize >= 1) {
/* Note: be careful about '\n' in value */
strncpy(value, xvalue, valuesize);
if (value[valuesize - 1] == '\n')
value[valuesize - 1] = 0;
if (value[valuesize - 1] != 0) {
fprintf(stderr, "Warning: skipping overly long value for entry that starts with %s=\"%s\".\n", xkey, xvalue);
} else {
result = strchr(value, '\n');
if (result != NULL)
*result = 0;
result = value;
break;
}
}
}
}
}
(void) fclose(f);
return result;
}
static const char* read_proc_cpuinfo_hardware_platform(char* value, size_t valuesize) {
return read_value_of_key_value_file(':', "/proc/cpuinfo", "Hardware", value, valuesize);
}
/** get_first_commandline_option_value: gets the value of the first (long) option with the specified name on the commandline and returns it.
* @param argv The argument "vector" from main()
* @param key The name of the option. Includes the "--" prefix
* @return Value of the option. NULL if it was not found */
static const char* get_first_commandline_option_value(char* argv[], const char* key) {
size_t keylen = strlen(key);
for (++argv; *argv != NULL; ++argv) {
const char* arg = *argv;
if (strncmp(arg, "--", strlen("--")) != 0)
break;
if (strncmp(arg, key, keylen) == 0) {
const char* value = &arg[keylen];
if (key[0] && key[strlen(key) - 1] == '=') {
return value;
} else if (*value == 0)
return value;
}
if (strcmp(arg, "--") == 0) /* end of options */
break;
}
return NULL;
}
/** get_first_commandline_argument: gets the value of the first commandline argument (i.e. the first non-option).
* @param argv The argument "vector" from main()
* @return Value of the argument. NULL if none is there. */
static const char* get_first_commandline_argument(char* argv[]) {
for (++argv; *argv != NULL; ++argv) {
const char* arg = *argv;
if (strncmp(arg, "--", strlen("--")) != 0)
break;
if (strcmp(arg, "--") == 0) /* end of options */ {
++argv;
break;
}
}
return *argv;
}
/** print_usage: Prints usage information to stderr.
* @param argv Argument "vector" from main() */
static void print_usage(char* argv[]) {
fprintf(stderr, "Usage: %s [--source-image=<name>] [--platform=<platform>] <drive>\n", argv[0] ?: "u-boot-install");
fprintf(stderr, "Usage: %s --list-platforms\n", argv[0] ?: "u-boot-install");
fprintf(stderr, "Usage: %s --list-drives\n", argv[0] ?: "u-boot-install");
fprintf(stderr, "If platform is not specified, it's autodetected by reading /proc/cpuinfo .\n");
fprintf(stderr, "<drive> is usually a block device of the drive.\n");
}
/** ensure_nonclobbering_slot: Ensures a free slot at start_Sectors, size size_Sectors which doesn't clobber anything else (or fails)
* @param drive Drive to use
* @param start_Sectors The start (in Sectors)
* @param size_Sectors The size (in Sectors) */
static void ensure_nonclobbering_slot(PedDevice* drive, PedSector start_Sectors, PedSector size_Sectors) {
/* TODO print drive model just to make sure */
/* TODO print char* size = ped_unit_format_byte (device, device->length * device->sector_size); */
const char* drivename = drive->path;
//long long sectorsize_Bytes = drive->sector_size;
PedDisk* disk = ped_disk_new(drive);
if (disk == NULL) {
fprintf(stderr, "Error: could not read partition table from \"%s\".\n", drivename);
exit(3);
}
for (PedPartition* part = ped_disk_next_partition(disk, NULL); part != NULL; part = ped_disk_next_partition(disk, part)) {
if (part->num < 0)
continue;
/* example:
1 2048 3563667087 ext4
2 3563669504 6291456
3 3569960960 143360000
4 3713320960 193708175 ext4 */
/* FIXME check unit */
printf("%d\t%lld\t%lld\t%s\n", part->num, part->geom.start, part->geom.length, part->fs_type ? part->fs_type->name : "");
}
{
int max_partition_count;
/* FIXME what's the difference to ped_disk_get_max_primary_partition_count ? */
if (!ped_disk_get_max_supported_partition_count(disk, &max_partition_count)) {
/* FIXME print error message */
abort();
}
if (max_partition_count > 56) { /* FIXME for disk type GPT;
static PedDisk *
gpt_duplicate (const PedDisk *disk);
see _generate_header which sets FirstUsableLBA = gpt_disk_data->data_area.start */
/* TODO if GPT is too large, reduce size of GPT to max. 56 entries. If it even is GPT to begin with (see disk->type).
That might entail copying all the things over to a new GPT.
*/
/* FirstUsableLBA is the first logical block that is used for contents */
abort();
}
/* FIXME gpt_partition_align (PedPartition *part, const PedConstraint *constraint) -> boooool */
}
/* FIXME check active gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state) PED_PARTITION_BOOT FIXME LEGACY_BOOT ?? */
ped_disk_destroy(disk);
}
/** write_block_safely: first makes sure there's nothing at the specified location, then writes there.
* @param drive Drive to write to
* @param buffer Buffer to read
* @param start_Bytes Location where to write to, in LBA bytes from the beginning of the disk
* @param size_Bytes Size of buffer and also number of bytes to write */
static void write_block_safely(PedDevice* drive, const void* buffer, off_t start_Bytes, off_t size_Bytes) {
const char* drivename = drive->path;
long long sectorsize_Bytes = drive->sector_size;
if (start_Bytes % sectorsize_Bytes != 0) {
fprintf(stderr, "Error: %jd Bytes from the start of drive %s is not the start of a sector. Cannot install there.\n", (intmax_t) start_Bytes, drivename);
exit(3);
}
PedSector start_Sectors = start_Bytes / sectorsize_Bytes;
PedSector size_Sectors = size_Bytes / sectorsize_Bytes; // FIXME round up.
ensure_nonclobbering_slot(drive, start_Sectors, size_Sectors);
if (ped_device_write(drive, buffer, start_Sectors, size_Sectors) == 0) {
/* FIXME print error message */
exit(4);
}
if (ped_device_sync(drive) == 0) {
/* FIXME print error message */
exit(5);
}
}
/** install_on_raw_drive: Installs U-Boot on Novena (i.MX6) devices
* @param imagename Name of the image to read
* @param drivename Name of the drive's block device (not partition)
* @param position_Bytes position to write the image to */
static void install_on_raw_drive(const char* imagename, const char* drivename, off_t position_Bytes) {
PedDevice* drive = ped_device_get(drivename);
if (drive == NULL) {
fprintf(stderr, "Error: could not open drive \"%s\".\n", drivename);
exit(2);
}
FILE* f = fopen(imagename, "rb");
long size_Bytes;
if (f == NULL ||
fseek(f, 0, SEEK_END) == -1 ||
(size_Bytes = ftell(f)) == -1 ||
fseek(f, 0, SEEK_SET) == -1) {
/* FIXME ferror, strerror */
exit(1);
}
if (size_Bytes > 8000000U) { /* 8 MB */
/* FIXME print Too big instead of allocating a huge buffer. */
abort();
}
void* buffer = malloc(size_Bytes);
if (buffer == NULL) {
fprintf(stderr, "ERROR: memory allocation of %ju bytes failed.\n", (uintmax_t) size_Bytes);
/* FIXME print error */
abort();
}
clearerr(f);
if (fread(buffer, size_Bytes, 1U, f) != 1) {
/* FIXME ferror, strerror.
fread() does not distinguish between end-of-file and error, and callers
must use feof(3) and ferror(3) to determine which occurred. */
abort();
}
write_block_safely(drive, buffer, position_Bytes, size_Bytes);
free(buffer);
(void) fclose(f);
ped_device_destroy(drive);
}
/** install_on_sunxi: Installs U-Boot on Allwinner (sunxi) devices
* @param argv Argument "vector" from main()
* @param drivename Name of the drive */
static void install_on_sunxi(char* argv[], const char* drivename) {
const char* imagename = get_first_commandline_option_value(argv, "--source-image=") ?: "u-boot-sunxi-with-spl.bin";
install_on_raw_drive(imagename, drivename, 8192ULL);
}
/** install_on_novena: Installs U-Boot on Novena (Freescale i.MX6) devices
* @param argv Argument "vector" from main()
* @param drivename Name of the drive */
static void install_on_novena(char* argv[], const char* drivename) {
const char* imagename = get_first_commandline_option_value(argv, "--source-image=") ?: "u-boot.spl";
install_on_raw_drive(imagename, drivename, 1024ULL);
}
/** struct installer: Represents an installer for a platform */
struct installer {
const char* platform;
void (*install)(char* argv[], const char* drive);
};
/** installers: Registry for known installers */
static struct installer installers[] = {
{.platform = "sun7i", install_on_sunxi},
{.platform = "mxc" /* imx6 */, install_on_novena},
// TODO {.platform = "uefi", install_on_uefi},
{}, /* sentinel */
};
/** install: Given a platform and drive, uses the platform-specific installer to install U-Boot on the drive.
* @param argv Argument "vector" from main()
* @param platform Name of the platform
* @param drive Name of the drive */
static void install(char* argv[], const char* platform, const char* drive) {
for (const struct installer* xinstallers = installers; xinstallers->platform != NULL; ++xinstallers) {
const struct installer* xinstaller = xinstallers;
const char* xplatform = xinstaller->platform;
if (strcmp(xplatform, platform) == 0) {
(*xinstaller->install)(argv, drive);
return;
}
}
fprintf(stderr, "Error: don't know how to install U-Boot on platform \"%s\".\n", platform);
exit(1);
}
/** list_platforms: Lists supported platforms */
static void list_platforms(void) {
for (const struct installer* xinstallers = installers; xinstallers->platform != NULL; ++xinstallers) {
const struct installer* xinstaller = xinstallers;
const char* xplatform = xinstaller->platform;
if (puts(xplatform) == EOF) {
/* FIXME print error message */
exit(1);
}
}
}
/** list_drives: Lists available drives */
static void list_drives(void) {
ped_device_probe_all();
for (PedDevice* device = ped_device_get_next(NULL); device != NULL; device = ped_device_get_next(device)) {
/* FIXME handle overflow. FIXME round properly. */
if (printf("%s\t%'lld MB\n", device->path, device->length * device->sector_size / 1000000) == -1) {
/* FIXME print error message */
exit(1);
}
}
}
static const char* get_uefi_platform(void) {
DIR* dir = opendir("/sys/firmware/efi/vars");
if (dir != NULL) {
closedir(dir);
return "uefi";
} else {
if (errno != ENOENT) {
perror("ERROR: /sys/firmware/efi/vars");
exit(9);
}
return NULL;
}
}
int main(int argc, char* argv[]) {
/* FIXME maybe make the user specify a --remote for remote installation and a --local for local installation - both mandatory */
char buf[200];
if (get_first_commandline_option_value(argv, "--help") != NULL) {
print_usage(argv);
return 0;
}
const char* oplist_platforms = get_first_commandline_option_value(argv, "--list-platforms");
if (oplist_platforms != NULL) {
list_platforms();
return 0;
} else {
const char* oplist_drives = get_first_commandline_option_value(argv, "--list-drives");
if (oplist_drives != NULL) {
list_drives();
return 0;
}
}
const char* platform = get_first_commandline_option_value(argv, "--platform=") ?:
get_uefi_platform() ?:
read_proc_cpuinfo_hardware_platform(buf, sizeof(buf));
const char* drive = get_first_commandline_argument(argv);
if (platform != NULL && drive != NULL) {
printf("Platform %s\n", platform);
printf("Drive %s\n", drive);
//printf("Hardware %s\n", read_proc_cpuinfo_hardware_platform(buf, sizeof(buf)));
install(argv, platform, drive);
} else {
print_usage(argv);
return 1;
}
return 0;
}
next prev parent reply other threads:[~2016-08-29 10:32 UTC|newest]
Thread overview: 69+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-08-05 18:37 [PATCH 02/12] import: utils: Symbols from 'license->symbol' have a license: prefix David Craven
2016-08-05 18:37 ` [PATCH 03/12] gnu: python: Import guix licenses with #:prefix license: David Craven
2016-08-05 18:37 ` [PATCH 04/12] gnu: python: Add python-binaryornot David Craven
2016-08-08 20:37 ` Leo Famulari
2016-08-22 12:05 ` David Craven
2016-08-22 12:14 ` David Craven
2016-08-22 13:20 ` [PATCH 01/11] import: utils: Symbols from 'license->symbol' have a license: prefix David Craven
2016-08-22 13:20 ` [PATCH 02/11] gnu: python: Import guix licenses with #:prefix license: David Craven
2016-08-26 20:55 ` David Craven
2016-08-22 13:20 ` [PATCH 03/11] gnu: Add python-binaryornot David Craven
2016-08-22 13:20 ` [PATCH 04/11] gnu: Add python-nltk David Craven
2016-08-27 8:39 ` Danny Milosavljevic
2016-10-24 21:15 ` Leo Famulari
2016-08-22 13:20 ` [PATCH 05/11] gnu: Add python-pymongo David Craven
2016-08-22 13:20 ` [PATCH 06/11] gnu: Add python-sh David Craven
2016-08-27 8:42 ` Danny Milosavljevic
2016-08-28 12:28 ` David Craven
2016-08-29 10:31 ` Danny Milosavljevic [this message]
2016-08-29 11:25 ` Guix with U-Boot David Craven
2016-08-29 14:12 ` David Craven
2016-08-29 14:19 ` Danny Milosavljevic
2016-08-29 16:51 ` David Craven
2016-08-29 17:20 ` Danny Milosavljevic
2016-08-29 17:52 ` Danny Milosavljevic
2016-08-29 18:10 ` Danny Milosavljevic
2016-08-29 17:38 ` Danny Milosavljevic
2016-08-29 18:16 ` Danny Milosavljevic
2016-08-29 18:20 ` David Craven
2016-08-29 18:56 ` David Craven
2016-08-29 19:04 ` Danny Milosavljevic
2016-08-29 18:57 ` How does install-grub work? Danny Milosavljevic
2016-08-29 20:29 ` David Craven
2016-08-29 20:50 ` Danny Milosavljevic
2016-08-29 20:54 ` David Craven
2016-08-29 21:19 ` David Craven
2016-08-29 21:57 ` Danny Milosavljevic
2016-08-29 22:00 ` David Craven
2016-08-29 22:14 ` Danny Milosavljevic
2016-08-30 15:33 ` David Craven
2016-08-29 21:45 ` Danny Milosavljevic
2016-08-29 22:04 ` Danny Milosavljevic
2016-08-22 13:20 ` [PATCH 07/11] gnu: Add python-schematics David Craven
2016-08-22 13:20 ` [PATCH 08/11] gnu: Add python-publicsuffix David Craven
2016-08-22 13:20 ` [PATCH 09/11] gnu: Add python-publicsuffix2 David Craven
2016-08-22 13:20 ` [PATCH 10/11] gnu: Add python-url David Craven
2016-08-22 13:20 ` [PATCH 11/11] gnu: Add python-ipaddress David Craven
2016-08-05 18:37 ` [PATCH 05/12] gnu: python: Add python-nltk David Craven
2016-08-05 18:37 ` [PATCH 06/12] gnu: python: Add python-pymongo David Craven
2016-08-08 20:36 ` Leo Famulari
2016-08-08 20:39 ` Leo Famulari
2016-08-05 18:37 ` [PATCH 07/12] gnu: python: Add python-sh David Craven
2016-08-05 18:37 ` [PATCH 08/12] gnu: python: Add python-schematics David Craven
2016-08-05 18:37 ` [PATCH 09/12] gnu: python: Add python-publicsuffix David Craven
2016-08-05 18:37 ` [PATCH 10/12] gnu: python: Add python-publicsuffix2 David Craven
2016-08-05 18:37 ` [PATCH 11/12] gnu: python: Add python-url David Craven
2016-08-05 18:37 ` [PATCH 12/12] gnu: python: Add python-ipaddress David Craven
2016-08-05 18:50 ` Leo Famulari
2016-08-06 12:52 ` David Craven
2016-08-06 15:57 ` Danny Milosavljevic
2016-08-07 0:20 ` Leo Famulari
2016-08-27 6:43 ` [PATCH 02/12] import: utils: Symbols from 'license->symbol' have a license: prefix Ricardo Wurmus
2016-08-27 8:31 ` David Craven
2016-08-30 19:07 ` Eric Bavier
2016-09-16 5:03 ` Eric Bavier
2016-09-16 7:29 ` David Craven
2016-09-16 15:40 ` Eric Bavier
2016-09-16 15:47 ` David Craven
2016-09-16 17:02 ` Eric Bavier
2016-09-19 13:06 ` Ludovic Courtès
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://guix.gnu.org/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20160829123149.0e260af6@scratchpost.org \
--to=dannym@scratchpost.org \
--cc=david@craven.ch \
--cc=guix-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/guix.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).