mmap_64.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /*
  2. * linux/arch/x86-64/mm/mmap.c
  3. *
  4. * flexible mmap layout support
  5. *
  6. * Based on code by Ingo Molnar and Andi Kleen, copyrighted
  7. * as follows:
  8. *
  9. * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
  10. * All Rights Reserved.
  11. * Copyright 2005 Andi Kleen, SUSE Labs.
  12. * Copyright 2007 Jiri Kosina, SUSE Labs.
  13. *
  14. * This program is free software; you can redistribute it and/or modify
  15. * it under the terms of the GNU General Public License as published by
  16. * the Free Software Foundation; either version 2 of the License, or
  17. * (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with this program; if not, write to the Free Software
  26. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  27. *
  28. */
  29. #include <linux/personality.h>
  30. #include <linux/mm.h>
  31. #include <linux/random.h>
  32. #include <linux/limits.h>
  33. #include <linux/sched.h>
  34. #include <asm/ia32.h>
  35. /*
  36. * Top of mmap area (just below the process stack).
  37. *
  38. * Leave an at least ~128 MB hole.
  39. */
  40. #define MIN_GAP (128*1024*1024)
  41. #define MAX_GAP (TASK_SIZE/6*5)
  42. static unsigned long mmap_base(void)
  43. {
  44. unsigned long gap = current->signal->rlim[RLIMIT_STACK].rlim_cur;
  45. if (gap < MIN_GAP)
  46. gap = MIN_GAP;
  47. else if (gap > MAX_GAP)
  48. gap = MAX_GAP;
  49. return TASK_SIZE - (gap & PAGE_MASK);
  50. }
  51. static int mmap_is_32(void)
  52. {
  53. #ifdef CONFIG_IA32_EMULATION
  54. if (test_thread_flag(TIF_IA32))
  55. return 1;
  56. #endif
  57. return 0;
  58. }
  59. static int mmap_is_legacy(void)
  60. {
  61. if (current->personality & ADDR_COMPAT_LAYOUT)
  62. return 1;
  63. if (current->signal->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY)
  64. return 1;
  65. return sysctl_legacy_va_layout;
  66. }
  67. /*
  68. * This function, called very early during the creation of a new
  69. * process VM image, sets up which VM layout function to use:
  70. */
  71. void arch_pick_mmap_layout(struct mm_struct *mm)
  72. {
  73. int rnd = 0;
  74. if (current->flags & PF_RANDOMIZE) {
  75. /*
  76. * Add 28bit randomness which is about 40bits of address space
  77. * because mmap base has to be page aligned.
  78. * or ~1/128 of the total user VM
  79. * (total user address space is 47bits)
  80. */
  81. rnd = get_random_int() & 0xfffffff;
  82. }
  83. /*
  84. * Fall back to the standard layout if the personality
  85. * bit is set, or if the expected stack growth is unlimited:
  86. */
  87. if (mmap_is_32()) {
  88. #ifdef CONFIG_IA32_EMULATION
  89. /* ia32_pick_mmap_layout has its own. */
  90. return ia32_pick_mmap_layout(mm);
  91. #endif
  92. } else if (mmap_is_legacy()) {
  93. mm->mmap_base = TASK_UNMAPPED_BASE;
  94. mm->get_unmapped_area = arch_get_unmapped_area;
  95. mm->unmap_area = arch_unmap_area;
  96. } else {
  97. mm->mmap_base = mmap_base();
  98. mm->get_unmapped_area = arch_get_unmapped_area_topdown;
  99. mm->unmap_area = arch_unmap_area_topdown;
  100. if (current->flags & PF_RANDOMIZE)
  101. rnd = -rnd;
  102. }
  103. if (current->flags & PF_RANDOMIZE)
  104. mm->mmap_base += ((long)rnd) << PAGE_SHIFT;
  105. }