diff options
Diffstat (limited to 'kernel/kexec.c')
-rw-r--r-- | kernel/kexec.c | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/kernel/kexec.c b/kernel/kexec.c index fbffdb457cce..aa74a1ef2da8 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c | |||
@@ -1146,6 +1146,172 @@ static int __init crash_notes_memory_init(void) | |||
1146 | } | 1146 | } |
1147 | module_init(crash_notes_memory_init) | 1147 | module_init(crash_notes_memory_init) |
1148 | 1148 | ||
1149 | |||
1150 | /* | ||
1151 | * parsing the "crashkernel" commandline | ||
1152 | * | ||
1153 | * this code is intended to be called from architecture specific code | ||
1154 | */ | ||
1155 | |||
1156 | |||
1157 | /* | ||
1158 | * This function parses command lines in the format | ||
1159 | * | ||
1160 | * crashkernel=ramsize-range:size[,...][@offset] | ||
1161 | * | ||
1162 | * The function returns 0 on success and -EINVAL on failure. | ||
1163 | */ | ||
1164 | static int __init parse_crashkernel_mem(char *cmdline, | ||
1165 | unsigned long long system_ram, | ||
1166 | unsigned long long *crash_size, | ||
1167 | unsigned long long *crash_base) | ||
1168 | { | ||
1169 | char *cur = cmdline, *tmp; | ||
1170 | |||
1171 | /* for each entry of the comma-separated list */ | ||
1172 | do { | ||
1173 | unsigned long long start, end = ULLONG_MAX, size; | ||
1174 | |||
1175 | /* get the start of the range */ | ||
1176 | start = memparse(cur, &tmp); | ||
1177 | if (cur == tmp) { | ||
1178 | pr_warning("crashkernel: Memory value expected\n"); | ||
1179 | return -EINVAL; | ||
1180 | } | ||
1181 | cur = tmp; | ||
1182 | if (*cur != '-') { | ||
1183 | pr_warning("crashkernel: '-' expected\n"); | ||
1184 | return -EINVAL; | ||
1185 | } | ||
1186 | cur++; | ||
1187 | |||
1188 | /* if no ':' is here, than we read the end */ | ||
1189 | if (*cur != ':') { | ||
1190 | end = memparse(cur, &tmp); | ||
1191 | if (cur == tmp) { | ||
1192 | pr_warning("crashkernel: Memory " | ||
1193 | "value expected\n"); | ||
1194 | return -EINVAL; | ||
1195 | } | ||
1196 | cur = tmp; | ||
1197 | if (end <= start) { | ||
1198 | pr_warning("crashkernel: end <= start\n"); | ||
1199 | return -EINVAL; | ||
1200 | } | ||
1201 | } | ||
1202 | |||
1203 | if (*cur != ':') { | ||
1204 | pr_warning("crashkernel: ':' expected\n"); | ||
1205 | return -EINVAL; | ||
1206 | } | ||
1207 | cur++; | ||
1208 | |||
1209 | size = memparse(cur, &tmp); | ||
1210 | if (cur == tmp) { | ||
1211 | pr_warning("Memory value expected\n"); | ||
1212 | return -EINVAL; | ||
1213 | } | ||
1214 | cur = tmp; | ||
1215 | if (size >= system_ram) { | ||
1216 | pr_warning("crashkernel: invalid size\n"); | ||
1217 | return -EINVAL; | ||
1218 | } | ||
1219 | |||
1220 | /* match ? */ | ||
1221 | if (system_ram >= start && system_ram <= end) { | ||
1222 | *crash_size = size; | ||
1223 | break; | ||
1224 | } | ||
1225 | } while (*cur++ == ','); | ||
1226 | |||
1227 | if (*crash_size > 0) { | ||
1228 | while (*cur != ' ' && *cur != '@') | ||
1229 | cur++; | ||
1230 | if (*cur == '@') { | ||
1231 | cur++; | ||
1232 | *crash_base = memparse(cur, &tmp); | ||
1233 | if (cur == tmp) { | ||
1234 | pr_warning("Memory value expected " | ||
1235 | "after '@'\n"); | ||
1236 | return -EINVAL; | ||
1237 | } | ||
1238 | } | ||
1239 | } | ||
1240 | |||
1241 | return 0; | ||
1242 | } | ||
1243 | |||
1244 | /* | ||
1245 | * That function parses "simple" (old) crashkernel command lines like | ||
1246 | * | ||
1247 | * crashkernel=size[@offset] | ||
1248 | * | ||
1249 | * It returns 0 on success and -EINVAL on failure. | ||
1250 | */ | ||
1251 | static int __init parse_crashkernel_simple(char *cmdline, | ||
1252 | unsigned long long *crash_size, | ||
1253 | unsigned long long *crash_base) | ||
1254 | { | ||
1255 | char *cur = cmdline; | ||
1256 | |||
1257 | *crash_size = memparse(cmdline, &cur); | ||
1258 | if (cmdline == cur) { | ||
1259 | pr_warning("crashkernel: memory value expected\n"); | ||
1260 | return -EINVAL; | ||
1261 | } | ||
1262 | |||
1263 | if (*cur == '@') | ||
1264 | *crash_base = memparse(cur+1, &cur); | ||
1265 | |||
1266 | return 0; | ||
1267 | } | ||
1268 | |||
1269 | /* | ||
1270 | * That function is the entry point for command line parsing and should be | ||
1271 | * called from the arch-specific code. | ||
1272 | */ | ||
1273 | int __init parse_crashkernel(char *cmdline, | ||
1274 | unsigned long long system_ram, | ||
1275 | unsigned long long *crash_size, | ||
1276 | unsigned long long *crash_base) | ||
1277 | { | ||
1278 | char *p = cmdline, *ck_cmdline = NULL; | ||
1279 | char *first_colon, *first_space; | ||
1280 | |||
1281 | BUG_ON(!crash_size || !crash_base); | ||
1282 | *crash_size = 0; | ||
1283 | *crash_base = 0; | ||
1284 | |||
1285 | /* find crashkernel and use the last one if there are more */ | ||
1286 | p = strstr(p, "crashkernel="); | ||
1287 | while (p) { | ||
1288 | ck_cmdline = p; | ||
1289 | p = strstr(p+1, "crashkernel="); | ||
1290 | } | ||
1291 | |||
1292 | if (!ck_cmdline) | ||
1293 | return -EINVAL; | ||
1294 | |||
1295 | ck_cmdline += 12; /* strlen("crashkernel=") */ | ||
1296 | |||
1297 | /* | ||
1298 | * if the commandline contains a ':', then that's the extended | ||
1299 | * syntax -- if not, it must be the classic syntax | ||
1300 | */ | ||
1301 | first_colon = strchr(ck_cmdline, ':'); | ||
1302 | first_space = strchr(ck_cmdline, ' '); | ||
1303 | if (first_colon && (!first_space || first_colon < first_space)) | ||
1304 | return parse_crashkernel_mem(ck_cmdline, system_ram, | ||
1305 | crash_size, crash_base); | ||
1306 | else | ||
1307 | return parse_crashkernel_simple(ck_cmdline, crash_size, | ||
1308 | crash_base); | ||
1309 | |||
1310 | return 0; | ||
1311 | } | ||
1312 | |||
1313 | |||
1314 | |||
1149 | void crash_save_vmcoreinfo(void) | 1315 | void crash_save_vmcoreinfo(void) |
1150 | { | 1316 | { |
1151 | u32 *buf; | 1317 | u32 *buf; |