summaryrefslogtreecommitdiff
path: root/cmd/sysboot.c
blob: 6344ecd357b3f92afeb1676727cea970e8f5bee4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// SPDX-License-Identifier: GPL-2.0+

#include <common.h>
#include <command.h>
#include <env.h>
#include <fs.h>
#include <pxe_utils.h>

static char *fs_argv[5];

static int do_get_ext2(struct pxe_context *ctx, const char *file_path,
		       char *file_addr, ulong *sizep)
{
#ifdef CONFIG_CMD_EXT2
	int ret;

	fs_argv[0] = "ext2load";
	fs_argv[3] = file_addr;
	fs_argv[4] = (void *)file_path;

	if (!do_ext2load(ctx->cmdtp, 0, 5, fs_argv))
		return 1;
	ret = pxe_get_file_size(sizep);
	if (ret)
		return log_msg_ret("tftp", ret);
#endif
	return -ENOENT;
}

static int do_get_fat(struct pxe_context *ctx, const char *file_path,
		      char *file_addr, ulong *sizep)
{
#ifdef CONFIG_CMD_FAT
	int ret;

	fs_argv[0] = "fatload";
	fs_argv[3] = file_addr;
	fs_argv[4] = (void *)file_path;

	if (!do_fat_fsload(ctx->cmdtp, 0, 5, fs_argv))
		return 1;
	ret = pxe_get_file_size(sizep);
	if (ret)
		return log_msg_ret("tftp", ret);
#endif
	return -ENOENT;
}

static int do_get_any(struct pxe_context *ctx, const char *file_path,
		      char *file_addr, ulong *sizep)
{
#ifdef CONFIG_CMD_FS_GENERIC
	int ret;

	fs_argv[0] = "load";
	fs_argv[3] = file_addr;
	fs_argv[4] = (void *)file_path;

	if (!do_load(ctx->cmdtp, 0, 5, fs_argv, FS_TYPE_ANY))
		return 1;
	ret = pxe_get_file_size(sizep);
	if (ret)
		return log_msg_ret("tftp", ret);
#endif
	return -ENOENT;
}

/*
 * Boots a system using a local disk syslinux/extlinux file
 *
 * Returns 0 on success, 1 on error.
 */
static int do_sysboot(struct cmd_tbl *cmdtp, int flag, int argc,
		      char *const argv[])
{
	unsigned long pxefile_addr_r;
	pxe_getfile_func getfile;
	struct pxe_context ctx;
	char *pxefile_addr_str;
	char *filename;
	int prompt = 0;
	int ret;

	if (argc > 1 && strstr(argv[1], "-p")) {
		prompt = 1;
		argc--;
		argv++;
	}

	if (argc < 4)
		return cmd_usage(cmdtp);

	if (argc < 5) {
		pxefile_addr_str = from_env("pxefile_addr_r");
		if (!pxefile_addr_str)
			return 1;
	} else {
		pxefile_addr_str = argv[4];
	}

	if (argc < 6) {
		filename = env_get("bootfile");
	} else {
		filename = argv[5];
		env_set("bootfile", filename);
	}

	if (strstr(argv[3], "ext2")) {
		getfile = do_get_ext2;
	} else if (strstr(argv[3], "fat")) {
		getfile = do_get_fat;
	} else if (strstr(argv[3], "any")) {
		getfile = do_get_any;
	} else {
		printf("Invalid filesystem: %s\n", argv[3]);
		return 1;
	}
	fs_argv[1] = argv[1];
	fs_argv[2] = argv[2];

	if (strict_strtoul(pxefile_addr_str, 16, &pxefile_addr_r) < 0) {
		printf("Invalid pxefile address: %s\n", pxefile_addr_str);
		return 1;
	}

	if (pxe_setup_ctx(&ctx, cmdtp, getfile, NULL, true, filename)) {
		printf("Out of memory\n");
		return CMD_RET_FAILURE;
	}

	if (get_pxe_file(&ctx, filename, pxefile_addr_r) < 0) {
		printf("Error reading config file\n");
		pxe_destroy_ctx(&ctx);
		return 1;
	}

	ret = pxe_process(&ctx, pxefile_addr_r, prompt);
	pxe_destroy_ctx(&ctx);
	if (ret)
		return CMD_RET_FAILURE;

	return 0;
}

U_BOOT_CMD(sysboot, 7, 1, do_sysboot,
	   "command to get and boot from syslinux files",
	   "[-p] <interface> <dev[:part]> <ext2|fat|any> [addr] [filename]\n"
	   "    - load and parse syslinux menu file 'filename' from ext2, fat\n"
	   "      or any filesystem on 'dev' on 'interface' to address 'addr'"
);