[PATCH v8 5/7] um: Discover host_task_size from envp

Tiwei Bie tiwei.btw at antgroup.com
Thu Sep 19 05:15:43 PDT 2024


On 2024/7/5 03:05, Benjamin Berg wrote:
[...]
> diff --git a/arch/x86/um/os-Linux/task_size.c b/arch/x86/um/os-Linux/task_size.c
> index 1dc9adc20b1c..a91599799b1a 100644
> --- a/arch/x86/um/os-Linux/task_size.c
> +++ b/arch/x86/um/os-Linux/task_size.c
> @@ -1,151 +1,19 @@
>  // SPDX-License-Identifier: GPL-2.0
> -#include <stdio.h>
> -#include <stdlib.h>
> -#include <signal.h>
> -#include <sys/mman.h>
> -#include <longjmp.h>
>  

Tiny nit: we need to include os.h to avoid below warning:

arch/x86/um/os-Linux/task_size.c:3:15: warning: no previous prototype for
‘os_get_top_address’ [-Wmissing-prototypes]
    3 | unsigned long os_get_top_address(char **envp)
      |               ^~~~~~~~~~~~~~~~~~

Regards,
Tiwei

> -#ifdef __i386__
> -
> -static jmp_buf buf;
> -
> -static void segfault(int sig)
> -{
> -	longjmp(buf, 1);
> -}
> -
> -static int page_ok(unsigned long page)
> -{
> -	unsigned long *address = (unsigned long *) (page << UM_KERN_PAGE_SHIFT);
> -	unsigned long n = ~0UL;
> -	void *mapped = NULL;
> -	int ok = 0;
> -
> -	/*
> -	 * First see if the page is readable.  If it is, it may still
> -	 * be a VDSO, so we go on to see if it's writable.  If not
> -	 * then try mapping memory there.  If that fails, then we're
> -	 * still in the kernel area.  As a sanity check, we'll fail if
> -	 * the mmap succeeds, but gives us an address different from
> -	 * what we wanted.
> -	 */
> -	if (setjmp(buf) == 0)
> -		n = *address;
> -	else {
> -		mapped = mmap(address, UM_KERN_PAGE_SIZE,
> -			      PROT_READ | PROT_WRITE,
> -			      MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
> -		if (mapped == MAP_FAILED)
> -			return 0;
> -		if (mapped != address)
> -			goto out;
> -	}
> -
> -	/*
> -	 * Now, is it writeable?  If so, then we're in user address
> -	 * space.  If not, then try mprotecting it and try the write
> -	 * again.
> -	 */
> -	if (setjmp(buf) == 0) {
> -		*address = n;
> -		ok = 1;
> -		goto out;
> -	} else if (mprotect(address, UM_KERN_PAGE_SIZE,
> -			    PROT_READ | PROT_WRITE) != 0)
> -		goto out;
> -
> -	if (setjmp(buf) == 0) {
> -		*address = n;
> -		ok = 1;
> -	}
> -
> - out:
> -	if (mapped != NULL)
> -		munmap(mapped, UM_KERN_PAGE_SIZE);
> -	return ok;
> -}
> -
> -unsigned long os_get_top_address(void)
> +unsigned long os_get_top_address(char **envp)
>  {
> -	struct sigaction sa, old;
> -	unsigned long bottom = 0;
> -	/*
> -	 * A 32-bit UML on a 64-bit host gets confused about the VDSO at
> -	 * 0xffffe000.  It is mapped, is readable, can be reprotected writeable
> -	 * and written.  However, exec discovers later that it can't be
> -	 * unmapped.  So, just set the highest address to be checked to just
> -	 * below it.  This might waste some address space on 4G/4G 32-bit
> -	 * hosts, but shouldn't hurt otherwise.
> -	 */
> -	unsigned long top = 0xffffd000 >> UM_KERN_PAGE_SHIFT;
> -	unsigned long test, original;
> +	unsigned long top_addr = (unsigned long) &top_addr;
> +	int i;
>  
> -	printf("Locating the bottom of the address space ... ");
> -	fflush(stdout);
> -
> -	/*
> -	 * We're going to be longjmping out of the signal handler, so
> -	 * SA_DEFER needs to be set.
> -	 */
> -	sa.sa_handler = segfault;
> -	sigemptyset(&sa.sa_mask);
> -	sa.sa_flags = SA_NODEFER;
> -	if (sigaction(SIGSEGV, &sa, &old)) {
> -		perror("os_get_top_address");
> -		exit(1);
> -	}
> -
> -	/* Manually scan the address space, bottom-up, until we find
> -	 * the first valid page (or run out of them).
> -	 */
> -	for (bottom = 0; bottom < top; bottom++) {
> -		if (page_ok(bottom))
> -			break;
> -	}
> -
> -	/* If we've got this far, we ran out of pages. */
> -	if (bottom == top) {
> -		fprintf(stderr, "Unable to determine bottom of address "
> -			"space.\n");
> -		exit(1);
> -	}
> -
> -	printf("0x%lx\n", bottom << UM_KERN_PAGE_SHIFT);
> -	printf("Locating the top of the address space ... ");
> -	fflush(stdout);
> -
> -	original = bottom;
> -
> -	/* This could happen with a 4G/4G split */
> -	if (page_ok(top))
> -		goto out;
> -
> -	do {
> -		test = bottom + (top - bottom) / 2;
> -		if (page_ok(test))
> -			bottom = test;
> -		else
> -			top = test;
> -	} while (top - bottom > 1);
> -
> -out:
> -	/* Restore the old SIGSEGV handling */
> -	if (sigaction(SIGSEGV, &old, NULL)) {
> -		perror("os_get_top_address");
> -		exit(1);
> +	/* The earliest variable should be after the program name in ELF */
> +	for (i = 0; envp[i]; i++) {
> +		if ((unsigned long) envp[i] > top_addr)
> +			top_addr = (unsigned long) envp[i];
>  	}
> -	top <<= UM_KERN_PAGE_SHIFT;
> -	printf("0x%lx\n", top);
>  
> -	return top;
> -}
> -
> -#else
> +	top_addr &= ~(UM_KERN_PAGE_SIZE - 1);
> +	top_addr += UM_KERN_PAGE_SIZE;
>  
> -unsigned long os_get_top_address(void)
> -{
> -	/* The old value of CONFIG_TOP_ADDR */
> -	return 0x7fc0002000;
> +	return top_addr;
>  }
>  
> -#endif




More information about the linux-um mailing list