Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

mm/memblock: Add "reserve_mem" to reserved named memory at boot up

In order to allow for requesting a memory region that can be used for
things like pstore on multiple machines where the memory layout is not the
same, add a new option to the kernel command line called "reserve_mem".

The format is: reserve_mem=nn:align:name

Where it will find nn amount of memory at the given alignment of align.
The name field is to allow another subsystem to retrieve where the memory
was found. For example:

reserve_mem=12M:4096:oops ramoops.mem_name=oops

Where ramoops.mem_name will tell ramoops that memory was reserved for it
via the reserve_mem option and it can find it by calling:

if (reserve_mem_find_by_name("oops", &start, &size)) {
// start holds the start address and size holds the size given

This is typically used for systems that do not wipe the RAM, and this
command line will try to reserve the same physical memory on soft reboots.
Note, it is not guaranteed to be the same location. For example, if KASLR
places the kernel at the location of where the RAM reservation was from a
previous boot, the new reservation will be at a different location. Any
subsystem using this feature must add a way to verify that the contents of
the physical memory is from a previous boot, as there may be cases where
the memory will not be located at the same location.

Not all systems may work either. There could be bit flips if the reboot
goes through the BIOS. Using kexec to reboot the machine is likely to
have better results in such cases.

Link: https://lore.kernel.org/all/ZjJVnZUX3NZiGW6q@kernel.org/

Suggested-by: Mike Rapoport <rppt@kernel.org>
Tested-by: Guilherme G. Piccoli <gpiccoli@igalia.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Link: https://lore.kernel.org/r/20240613155527.437020271@goodmis.org
Signed-off-by: Mike Rapoport (IBM) <rppt@kernel.org>

authored by

Steven Rostedt (Google) and committed by
Mike Rapoport (IBM)
1e4c64b7 0e9899fe

+141
+22
Documentation/admin-guide/kernel-parameters.txt
··· 5710 5710 them. If <base> is less than 0x10000, the region 5711 5711 is assumed to be I/O ports; otherwise it is memory. 5712 5712 5713 + reserve_mem= [RAM] 5714 + Format: nn[KNG]:<align>:<label> 5715 + Reserve physical memory and label it with a name that 5716 + other subsystems can use to access it. This is typically 5717 + used for systems that do not wipe the RAM, and this command 5718 + line will try to reserve the same physical memory on 5719 + soft reboots. Note, it is not guaranteed to be the same 5720 + location. For example, if anything about the system changes 5721 + or if booting a different kernel. It can also fail if KASLR 5722 + places the kernel at the location of where the RAM reservation 5723 + was from a previous boot, the new reservation will be at a 5724 + different location. 5725 + Any subsystem using this feature must add a way to verify 5726 + that the contents of the physical memory is from a previous 5727 + boot, as there may be cases where the memory will not be 5728 + located at the same location. 5729 + 5730 + The format is size:align:label for example, to request 5731 + 12 megabytes of 4096 alignment for ramoops: 5732 + 5733 + reserve_mem=12M:4096:oops ramoops.mem_name=oops 5734 + 5713 5735 reservetop= [X86-32,EARLY] 5714 5736 Format: nn[KMG] 5715 5737 Reserves a hole at the top of the kernel virtual
+2
include/linux/mm.h
··· 4263 4263 void vma_pgtable_walk_begin(struct vm_area_struct *vma); 4264 4264 void vma_pgtable_walk_end(struct vm_area_struct *vma); 4265 4265 4266 + int reserve_mem_find_by_name(const char *name, phys_addr_t *start, phys_addr_t *size); 4267 + 4266 4268 #endif /* _LINUX_MM_H */
+117
mm/memblock.c
··· 2242 2242 totalram_pages_add(pages); 2243 2243 } 2244 2244 2245 + /* Keep a table to reserve named memory */ 2246 + #define RESERVE_MEM_MAX_ENTRIES 8 2247 + #define RESERVE_MEM_NAME_SIZE 16 2248 + struct reserve_mem_table { 2249 + char name[RESERVE_MEM_NAME_SIZE]; 2250 + phys_addr_t start; 2251 + phys_addr_t size; 2252 + }; 2253 + static struct reserve_mem_table reserved_mem_table[RESERVE_MEM_MAX_ENTRIES]; 2254 + static int reserved_mem_count; 2255 + 2256 + /* Add wildcard region with a lookup name */ 2257 + static void __init reserved_mem_add(phys_addr_t start, phys_addr_t size, 2258 + const char *name) 2259 + { 2260 + struct reserve_mem_table *map; 2261 + 2262 + map = &reserved_mem_table[reserved_mem_count++]; 2263 + map->start = start; 2264 + map->size = size; 2265 + strscpy(map->name, name); 2266 + } 2267 + 2268 + /** 2269 + * reserve_mem_find_by_name - Find reserved memory region with a given name 2270 + * @name: The name that is attached to a reserved memory region 2271 + * @start: If found, holds the start address 2272 + * @size: If found, holds the size of the address. 2273 + * 2274 + * @start and @size are only updated if @name is found. 2275 + * 2276 + * Returns: 1 if found or 0 if not found. 2277 + */ 2278 + int reserve_mem_find_by_name(const char *name, phys_addr_t *start, phys_addr_t *size) 2279 + { 2280 + struct reserve_mem_table *map; 2281 + int i; 2282 + 2283 + for (i = 0; i < reserved_mem_count; i++) { 2284 + map = &reserved_mem_table[i]; 2285 + if (!map->size) 2286 + continue; 2287 + if (strcmp(name, map->name) == 0) { 2288 + *start = map->start; 2289 + *size = map->size; 2290 + return 1; 2291 + } 2292 + } 2293 + return 0; 2294 + } 2295 + EXPORT_SYMBOL_GPL(reserve_mem_find_by_name); 2296 + 2297 + /* 2298 + * Parse reserve_mem=nn:align:name 2299 + */ 2300 + static int __init reserve_mem(char *p) 2301 + { 2302 + phys_addr_t start, size, align, tmp; 2303 + char *name; 2304 + char *oldp; 2305 + int len; 2306 + 2307 + if (!p) 2308 + return -EINVAL; 2309 + 2310 + /* Check if there's room for more reserved memory */ 2311 + if (reserved_mem_count >= RESERVE_MEM_MAX_ENTRIES) 2312 + return -EBUSY; 2313 + 2314 + oldp = p; 2315 + size = memparse(p, &p); 2316 + if (!size || p == oldp) 2317 + return -EINVAL; 2318 + 2319 + if (*p != ':') 2320 + return -EINVAL; 2321 + 2322 + align = memparse(p+1, &p); 2323 + if (*p != ':') 2324 + return -EINVAL; 2325 + 2326 + /* 2327 + * memblock_phys_alloc() doesn't like a zero size align, 2328 + * but it is OK for this command to have it. 2329 + */ 2330 + if (align < SMP_CACHE_BYTES) 2331 + align = SMP_CACHE_BYTES; 2332 + 2333 + name = p + 1; 2334 + len = strlen(name); 2335 + 2336 + /* name needs to have length but not too big */ 2337 + if (!len || len >= RESERVE_MEM_NAME_SIZE) 2338 + return -EINVAL; 2339 + 2340 + /* Make sure that name has text */ 2341 + for (p = name; *p; p++) { 2342 + if (!isspace(*p)) 2343 + break; 2344 + } 2345 + if (!*p) 2346 + return -EINVAL; 2347 + 2348 + /* Make sure the name is not already used */ 2349 + if (reserve_mem_find_by_name(name, &start, &tmp)) 2350 + return -EBUSY; 2351 + 2352 + start = memblock_phys_alloc(size, align); 2353 + if (!start) 2354 + return -ENOMEM; 2355 + 2356 + reserved_mem_add(start, size, name); 2357 + 2358 + return 1; 2359 + } 2360 + __setup("reserve_mem=", reserve_mem); 2361 + 2245 2362 #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_ARCH_KEEP_MEMBLOCK) 2246 2363 static const char * const flagname[] = { 2247 2364 [ilog2(MEMBLOCK_HOTPLUG)] = "HOTPLUG",