|
|
1.1 root 1: /*
2: * Copyright (c) 2010-2014 Richard Braun.
3: *
4: * This program is free software: you can redistribute it and/or modify
5: * it under the terms of the GNU General Public License as published by
6: * the Free Software Foundation, either version 2 of the License, or
7: * (at your option) any later version.
8: *
9: * This program is distributed in the hope that it will be useful,
10: * but WITHOUT ANY WARRANTY; without even the implied warranty of
11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12: * GNU General Public License for more details.
13: *
14: * You should have received a copy of the GNU General Public License
15: * along with this program. If not, see <http://www.gnu.org/licenses/>.
16: *
17: *
18: * This implementation uses the binary buddy system to manage its heap.
19: * Descriptions of the buddy system can be found in the following works :
20: * - "UNIX Internals: The New Frontiers", by Uresh Vahalia.
21: * - "Dynamic Storage Allocation: A Survey and Critical Review",
22: * by Paul R. Wilson, Mark S. Johnstone, Michael Neely, and David Boles.
23: *
24: * In addition, this allocator uses per-CPU pools of pages for order 0
25: * (i.e. single page) allocations. These pools act as caches (but are named
26: * differently to avoid confusion with CPU caches) that reduce contention on
27: * multiprocessor systems. When a pool is empty and cannot provide a page,
28: * it is filled by transferring multiple pages from the backend buddy system.
29: * The symmetric case is handled likewise.
30: */
31:
32: #include <string.h>
33: #include <kern/assert.h>
34: #include <kern/cpu_number.h>
35: #include <kern/debug.h>
36: #include <kern/list.h>
37: #include <kern/lock.h>
38: #include <kern/macros.h>
39: #include <kern/printf.h>
40: #include <kern/thread.h>
41: #include <mach/vm_param.h>
42: #include <machine/pmap.h>
43: #include <sys/types.h>
44: #include <vm/vm_page.h>
45:
46: #define __init
47: #define __initdata
48: #define __read_mostly
49:
50: #define thread_pin()
51: #define thread_unpin()
52:
53: /*
54: * Number of free block lists per segment.
55: */
56: #define VM_PAGE_NR_FREE_LISTS 11
57:
58: /*
59: * The size of a CPU pool is computed by dividing the number of pages in its
60: * containing segment by this value.
61: */
62: #define VM_PAGE_CPU_POOL_RATIO 1024
63:
64: /*
65: * Maximum number of pages in a CPU pool.
66: */
67: #define VM_PAGE_CPU_POOL_MAX_SIZE 128
68:
69: /*
70: * The transfer size of a CPU pool is computed by dividing the pool size by
71: * this value.
72: */
73: #define VM_PAGE_CPU_POOL_TRANSFER_RATIO 2
74:
75: /*
76: * Per-processor cache of pages.
77: */
78: struct vm_page_cpu_pool {
79: simple_lock_data_t lock;
80: int size;
81: int transfer_size;
82: int nr_pages;
83: struct list pages;
84: } __aligned(CPU_L1_SIZE);
85:
86: /*
87: * Special order value for pages that aren't in a free list. Such pages are
88: * either allocated, or part of a free block of pages but not the head page.
89: */
90: #define VM_PAGE_ORDER_UNLISTED ((unsigned short)-1)
91:
92: /*
93: * Doubly-linked list of free blocks.
94: */
95: struct vm_page_free_list {
96: unsigned long size;
97: struct list blocks;
98: };
99:
100: /*
101: * Segment name buffer size.
102: */
103: #define VM_PAGE_NAME_SIZE 16
104:
105: /*
106: * Segment of contiguous memory.
107: */
108: struct vm_page_seg {
109: struct vm_page_cpu_pool cpu_pools[NCPUS];
110:
111: phys_addr_t start;
112: phys_addr_t end;
113: struct vm_page *pages;
114: struct vm_page *pages_end;
115: simple_lock_data_t lock;
116: struct vm_page_free_list free_lists[VM_PAGE_NR_FREE_LISTS];
117: unsigned long nr_free_pages;
118: };
119:
120: /*
121: * Bootstrap information about a segment.
122: */
123: struct vm_page_boot_seg {
124: phys_addr_t start;
125: phys_addr_t end;
126: phys_addr_t avail_start;
127: phys_addr_t avail_end;
128: };
129:
130: static int vm_page_is_ready __read_mostly;
131:
132: /*
133: * Segment table.
134: *
135: * The system supports a maximum of 4 segments :
136: * - DMA: suitable for DMA
137: * - DMA32: suitable for DMA when devices support 32-bits addressing
138: * - DIRECTMAP: direct physical mapping, allows direct access from
139: * the kernel with a simple offset translation
140: * - HIGHMEM: must be mapped before it can be accessed
141: *
142: * Segments are ordered by priority, 0 being the lowest priority. Their
143: * relative priorities are DMA < DMA32 < DIRECTMAP < HIGHMEM. Some segments
144: * may actually be aliases for others, e.g. if DMA is always possible from
145: * the direct physical mapping, DMA and DMA32 are aliases for DIRECTMAP,
146: * in which case the segment table contains DIRECTMAP and HIGHMEM only.
147: */
148: static struct vm_page_seg vm_page_segs[VM_PAGE_MAX_SEGS];
149:
150: /*
151: * Bootstrap segment table.
152: */
153: static struct vm_page_boot_seg vm_page_boot_segs[VM_PAGE_MAX_SEGS] __initdata;
154:
155: /*
156: * Number of loaded segments.
157: */
158: static unsigned int vm_page_segs_size __read_mostly;
159:
160: static void __init
161: vm_page_init_pa(struct vm_page *page, unsigned short seg_index, phys_addr_t pa)
162: {
163: memset(page, 0, sizeof(*page));
164: vm_page_init(page); /* vm_resident members */
165: page->type = VM_PT_RESERVED;
166: page->seg_index = seg_index;
167: page->order = VM_PAGE_ORDER_UNLISTED;
168: page->priv = NULL;
169: page->phys_addr = pa;
170: }
171:
172: void
173: vm_page_set_type(struct vm_page *page, unsigned int order, unsigned short type)
174: {
175: unsigned int i, nr_pages;
176:
177: nr_pages = 1 << order;
178:
179: for (i = 0; i < nr_pages; i++)
180: page[i].type = type;
181: }
182:
183: static void __init
184: vm_page_free_list_init(struct vm_page_free_list *free_list)
185: {
186: free_list->size = 0;
187: list_init(&free_list->blocks);
188: }
189:
190: static inline void
191: vm_page_free_list_insert(struct vm_page_free_list *free_list,
192: struct vm_page *page)
193: {
194: assert(page->order == VM_PAGE_ORDER_UNLISTED);
195:
196: free_list->size++;
197: list_insert_head(&free_list->blocks, &page->node);
198: }
199:
200: static inline void
201: vm_page_free_list_remove(struct vm_page_free_list *free_list,
202: struct vm_page *page)
203: {
204: assert(page->order != VM_PAGE_ORDER_UNLISTED);
205:
206: free_list->size--;
207: list_remove(&page->node);
208: }
209:
210: static struct vm_page *
211: vm_page_seg_alloc_from_buddy(struct vm_page_seg *seg, unsigned int order)
212: {
213: struct vm_page_free_list *free_list = free_list;
214: struct vm_page *page, *buddy;
215: unsigned int i;
216:
217: assert(order < VM_PAGE_NR_FREE_LISTS);
218:
219: for (i = order; i < VM_PAGE_NR_FREE_LISTS; i++) {
220: free_list = &seg->free_lists[i];
221:
222: if (free_list->size != 0)
223: break;
224: }
225:
226: if (i == VM_PAGE_NR_FREE_LISTS)
227: return NULL;
228:
229: page = list_first_entry(&free_list->blocks, struct vm_page, node);
230: vm_page_free_list_remove(free_list, page);
231: page->order = VM_PAGE_ORDER_UNLISTED;
232:
233: while (i > order) {
234: i--;
235: buddy = &page[1 << i];
236: vm_page_free_list_insert(&seg->free_lists[i], buddy);
237: buddy->order = i;
238: }
239:
240: seg->nr_free_pages -= (1 << order);
241: return page;
242: }
243:
244: static void
245: vm_page_seg_free_to_buddy(struct vm_page_seg *seg, struct vm_page *page,
246: unsigned int order)
247: {
248: struct vm_page *buddy;
249: phys_addr_t pa, buddy_pa;
250: unsigned int nr_pages;
251:
252: assert(page >= seg->pages);
253: assert(page < seg->pages_end);
254: assert(page->order == VM_PAGE_ORDER_UNLISTED);
255: assert(order < VM_PAGE_NR_FREE_LISTS);
256:
257: nr_pages = (1 << order);
258: pa = page->phys_addr;
259:
260: while (order < (VM_PAGE_NR_FREE_LISTS - 1)) {
261: buddy_pa = pa ^ vm_page_ptoa(1 << order);
262:
263: if ((buddy_pa < seg->start) || (buddy_pa >= seg->end))
264: break;
265:
266: buddy = &seg->pages[vm_page_atop(buddy_pa - seg->start)];
267:
268: if (buddy->order != order)
269: break;
270:
271: vm_page_free_list_remove(&seg->free_lists[order], buddy);
272: buddy->order = VM_PAGE_ORDER_UNLISTED;
273: order++;
274: pa &= -vm_page_ptoa(1 << order);
275: page = &seg->pages[vm_page_atop(pa - seg->start)];
276: }
277:
278: vm_page_free_list_insert(&seg->free_lists[order], page);
279: page->order = order;
280: seg->nr_free_pages += nr_pages;
281: }
282:
283: static void __init
284: vm_page_cpu_pool_init(struct vm_page_cpu_pool *cpu_pool, int size)
285: {
286: simple_lock_init(&cpu_pool->lock);
287: cpu_pool->size = size;
288: cpu_pool->transfer_size = (size + VM_PAGE_CPU_POOL_TRANSFER_RATIO - 1)
289: / VM_PAGE_CPU_POOL_TRANSFER_RATIO;
290: cpu_pool->nr_pages = 0;
291: list_init(&cpu_pool->pages);
292: }
293:
294: static inline struct vm_page_cpu_pool *
295: vm_page_cpu_pool_get(struct vm_page_seg *seg)
296: {
297: return &seg->cpu_pools[cpu_number()];
298: }
299:
300: static inline struct vm_page *
301: vm_page_cpu_pool_pop(struct vm_page_cpu_pool *cpu_pool)
302: {
303: struct vm_page *page;
304:
305: assert(cpu_pool->nr_pages != 0);
306: cpu_pool->nr_pages--;
307: page = list_first_entry(&cpu_pool->pages, struct vm_page, node);
308: list_remove(&page->node);
309: return page;
310: }
311:
312: static inline void
313: vm_page_cpu_pool_push(struct vm_page_cpu_pool *cpu_pool, struct vm_page *page)
314: {
315: assert(cpu_pool->nr_pages < cpu_pool->size);
316: cpu_pool->nr_pages++;
317: list_insert_head(&cpu_pool->pages, &page->node);
318: }
319:
320: static int
321: vm_page_cpu_pool_fill(struct vm_page_cpu_pool *cpu_pool,
322: struct vm_page_seg *seg)
323: {
324: struct vm_page *page;
325: int i;
326:
327: assert(cpu_pool->nr_pages == 0);
328:
329: simple_lock(&seg->lock);
330:
331: for (i = 0; i < cpu_pool->transfer_size; i++) {
332: page = vm_page_seg_alloc_from_buddy(seg, 0);
333:
334: if (page == NULL)
335: break;
336:
337: vm_page_cpu_pool_push(cpu_pool, page);
338: }
339:
340: simple_unlock(&seg->lock);
341:
342: return i;
343: }
344:
345: static void
346: vm_page_cpu_pool_drain(struct vm_page_cpu_pool *cpu_pool,
347: struct vm_page_seg *seg)
348: {
349: struct vm_page *page;
350: int i;
351:
352: assert(cpu_pool->nr_pages == cpu_pool->size);
353:
354: simple_lock(&seg->lock);
355:
356: for (i = cpu_pool->transfer_size; i > 0; i--) {
357: page = vm_page_cpu_pool_pop(cpu_pool);
358: vm_page_seg_free_to_buddy(seg, page, 0);
359: }
360:
361: simple_unlock(&seg->lock);
362: }
363:
364: static phys_addr_t __init
365: vm_page_seg_size(struct vm_page_seg *seg)
366: {
367: return seg->end - seg->start;
368: }
369:
370: static int __init
371: vm_page_seg_compute_pool_size(struct vm_page_seg *seg)
372: {
373: phys_addr_t size;
374:
375: size = vm_page_atop(vm_page_seg_size(seg)) / VM_PAGE_CPU_POOL_RATIO;
376:
377: if (size == 0)
378: size = 1;
379: else if (size > VM_PAGE_CPU_POOL_MAX_SIZE)
380: size = VM_PAGE_CPU_POOL_MAX_SIZE;
381:
382: return size;
383: }
384:
385: static void __init
386: vm_page_seg_init(struct vm_page_seg *seg, phys_addr_t start, phys_addr_t end,
387: struct vm_page *pages)
388: {
389: phys_addr_t pa;
390: int pool_size;
391: unsigned int i;
392:
393: seg->start = start;
394: seg->end = end;
395: pool_size = vm_page_seg_compute_pool_size(seg);
396:
397: for (i = 0; i < ARRAY_SIZE(seg->cpu_pools); i++)
398: vm_page_cpu_pool_init(&seg->cpu_pools[i], pool_size);
399:
400: seg->pages = pages;
401: seg->pages_end = pages + vm_page_atop(vm_page_seg_size(seg));
402: simple_lock_init(&seg->lock);
403:
404: for (i = 0; i < ARRAY_SIZE(seg->free_lists); i++)
405: vm_page_free_list_init(&seg->free_lists[i]);
406:
407: seg->nr_free_pages = 0;
408: i = seg - vm_page_segs;
409:
410: for (pa = seg->start; pa < seg->end; pa += PAGE_SIZE)
411: vm_page_init_pa(&pages[vm_page_atop(pa - seg->start)], i, pa);
412: }
413:
414: static struct vm_page *
415: vm_page_seg_alloc(struct vm_page_seg *seg, unsigned int order,
416: unsigned short type)
417: {
418: struct vm_page_cpu_pool *cpu_pool;
419: struct vm_page *page;
420: int filled;
421:
422: assert(order < VM_PAGE_NR_FREE_LISTS);
423:
424: if (order == 0) {
425: thread_pin();
426: cpu_pool = vm_page_cpu_pool_get(seg);
427: simple_lock(&cpu_pool->lock);
428:
429: if (cpu_pool->nr_pages == 0) {
430: filled = vm_page_cpu_pool_fill(cpu_pool, seg);
431:
432: if (!filled) {
433: simple_unlock(&cpu_pool->lock);
434: thread_unpin();
435: return NULL;
436: }
437: }
438:
439: page = vm_page_cpu_pool_pop(cpu_pool);
440: simple_unlock(&cpu_pool->lock);
441: thread_unpin();
442: } else {
443: simple_lock(&seg->lock);
444: page = vm_page_seg_alloc_from_buddy(seg, order);
445: simple_unlock(&seg->lock);
446:
447: if (page == NULL)
448: return NULL;
449: }
450:
451: assert(page->type == VM_PT_FREE);
452: vm_page_set_type(page, order, type);
453: return page;
454: }
455:
456: static void
457: vm_page_seg_free(struct vm_page_seg *seg, struct vm_page *page,
458: unsigned int order)
459: {
460: struct vm_page_cpu_pool *cpu_pool;
461:
462: assert(page->type != VM_PT_FREE);
463: assert(order < VM_PAGE_NR_FREE_LISTS);
464:
465: vm_page_set_type(page, order, VM_PT_FREE);
466:
467: if (order == 0) {
468: thread_pin();
469: cpu_pool = vm_page_cpu_pool_get(seg);
470: simple_lock(&cpu_pool->lock);
471:
472: if (cpu_pool->nr_pages == cpu_pool->size)
473: vm_page_cpu_pool_drain(cpu_pool, seg);
474:
475: vm_page_cpu_pool_push(cpu_pool, page);
476: simple_unlock(&cpu_pool->lock);
477: thread_unpin();
478: } else {
479: simple_lock(&seg->lock);
480: vm_page_seg_free_to_buddy(seg, page, order);
481: simple_unlock(&seg->lock);
482: }
483: }
484:
485: void __init
486: vm_page_load(unsigned int seg_index, phys_addr_t start, phys_addr_t end,
487: phys_addr_t avail_start, phys_addr_t avail_end)
488: {
489: struct vm_page_boot_seg *seg;
490:
491: assert(seg_index < ARRAY_SIZE(vm_page_boot_segs));
492: assert(vm_page_aligned(start));
493: assert(vm_page_aligned(end));
494: assert(vm_page_aligned(avail_start));
495: assert(vm_page_aligned(avail_end));
496: assert(start < end);
497: assert(start <= avail_start);
498: assert(avail_end <= end);
499: assert(vm_page_segs_size < ARRAY_SIZE(vm_page_boot_segs));
500:
501: seg = &vm_page_boot_segs[seg_index];
502: seg->start = start;
503: seg->end = end;
504: seg->avail_start = avail_start;
505: seg->avail_end = avail_end;
506: vm_page_segs_size++;
507: }
508:
509: int
510: vm_page_ready(void)
511: {
512: return vm_page_is_ready;
513: }
514:
515: static unsigned int
516: vm_page_select_alloc_seg(unsigned int selector)
517: {
518: unsigned int seg_index;
519:
520: switch (selector) {
521: case VM_PAGE_SEL_DMA:
522: seg_index = VM_PAGE_SEG_DMA;
523: break;
524: case VM_PAGE_SEL_DMA32:
525: seg_index = VM_PAGE_SEG_DMA32;
526: break;
527: case VM_PAGE_SEL_DIRECTMAP:
528: seg_index = VM_PAGE_SEG_DIRECTMAP;
529: break;
530: case VM_PAGE_SEL_HIGHMEM:
531: seg_index = VM_PAGE_SEG_HIGHMEM;
532: break;
533: default:
534: panic("vm_page: invalid selector");
535: }
536:
537: return MIN(vm_page_segs_size - 1, seg_index);
538: }
539:
540: static int __init
541: vm_page_boot_seg_loaded(const struct vm_page_boot_seg *seg)
542: {
543: return (seg->end != 0);
544: }
545:
546: static void __init
547: vm_page_check_boot_segs(void)
548: {
549: unsigned int i;
550: int expect_loaded;
551:
552: if (vm_page_segs_size == 0)
553: panic("vm_page: no physical memory loaded");
554:
555: for (i = 0; i < ARRAY_SIZE(vm_page_boot_segs); i++) {
556: expect_loaded = (i < vm_page_segs_size);
557:
558: if (vm_page_boot_seg_loaded(&vm_page_boot_segs[i]) == expect_loaded)
559: continue;
560:
561: panic("vm_page: invalid boot segment table");
562: }
563: }
564:
565: static phys_addr_t __init
566: vm_page_boot_seg_size(struct vm_page_boot_seg *seg)
567: {
568: return seg->end - seg->start;
569: }
570:
571: static phys_addr_t __init
572: vm_page_boot_seg_avail_size(struct vm_page_boot_seg *seg)
573: {
574: return seg->avail_end - seg->avail_start;
575: }
576:
577: unsigned long __init
578: vm_page_bootalloc(size_t size)
579: {
580: struct vm_page_boot_seg *seg;
581: phys_addr_t pa;
582: unsigned int i;
583:
584: for (i = vm_page_select_alloc_seg(VM_PAGE_SEL_DIRECTMAP);
585: i < vm_page_segs_size;
586: i--) {
587: seg = &vm_page_boot_segs[i];
588:
589: if (size <= vm_page_boot_seg_avail_size(seg)) {
590: pa = seg->avail_start;
591: seg->avail_start += vm_page_round(size);
592: return pa;
593: }
594: }
595:
596: panic("vm_page: no physical memory available");
597: }
598:
599: void __init
600: vm_page_setup(void)
601: {
602: struct vm_page_boot_seg *boot_seg;
603: struct vm_page_seg *seg;
604: struct vm_page *table, *page, *end;
605: size_t nr_pages, table_size;
606: unsigned long va;
607: unsigned int i;
608: phys_addr_t pa;
609:
610: vm_page_check_boot_segs();
611:
612: /*
613: * Compute the page table size.
614: */
615: nr_pages = 0;
616:
617: for (i = 0; i < vm_page_segs_size; i++)
618: nr_pages += vm_page_atop(vm_page_boot_seg_size(&vm_page_boot_segs[i]));
619:
620: table_size = vm_page_round(nr_pages * sizeof(struct vm_page));
621: printf("vm_page: page table size: %lu entries (%luk)\n", nr_pages,
622: table_size >> 10);
623: table = (struct vm_page *)pmap_steal_memory(table_size);
624: va = (unsigned long)table;
625:
626: /*
627: * Initialize the segments, associating them to the page table. When
628: * the segments are initialized, all their pages are set allocated.
629: * Pages are then released, which populates the free lists.
630: */
631: for (i = 0; i < vm_page_segs_size; i++) {
632: seg = &vm_page_segs[i];
633: boot_seg = &vm_page_boot_segs[i];
634: vm_page_seg_init(seg, boot_seg->start, boot_seg->end, table);
635: page = seg->pages + vm_page_atop(boot_seg->avail_start
636: - boot_seg->start);
637: end = seg->pages + vm_page_atop(boot_seg->avail_end
638: - boot_seg->start);
639:
640: while (page < end) {
641: page->type = VM_PT_FREE;
642: vm_page_seg_free_to_buddy(seg, page, 0);
643: page++;
644: }
645:
646: table += vm_page_atop(vm_page_seg_size(seg));
647: }
648:
649: while (va < (unsigned long)table) {
650: pa = pmap_extract(kernel_pmap, va);
651: page = vm_page_lookup_pa(pa);
652: assert((page != NULL) && (page->type == VM_PT_RESERVED));
653: page->type = VM_PT_TABLE;
654: va += PAGE_SIZE;
655: }
656:
657: vm_page_is_ready = 1;
658: }
659:
660: void __init
661: vm_page_manage(struct vm_page *page)
662: {
663: assert(page->seg_index < ARRAY_SIZE(vm_page_segs));
664: assert(page->type == VM_PT_RESERVED);
665:
666: vm_page_set_type(page, 0, VM_PT_FREE);
667: vm_page_seg_free_to_buddy(&vm_page_segs[page->seg_index], page, 0);
668: }
669:
670: struct vm_page *
671: vm_page_lookup_pa(phys_addr_t pa)
672: {
673: struct vm_page_seg *seg;
674: unsigned int i;
675:
676: for (i = 0; i < vm_page_segs_size; i++) {
677: seg = &vm_page_segs[i];
678:
679: if ((pa >= seg->start) && (pa < seg->end))
680: return &seg->pages[vm_page_atop(pa - seg->start)];
681: }
682:
683: return NULL;
684: }
685:
686: struct vm_page *
687: vm_page_alloc_pa(unsigned int order, unsigned int selector, unsigned short type)
688: {
689: struct vm_page *page;
690: unsigned int i;
691:
692: for (i = vm_page_select_alloc_seg(selector); i < vm_page_segs_size; i--) {
693: page = vm_page_seg_alloc(&vm_page_segs[i], order, type);
694:
695: if (page != NULL)
696: return page;
697: }
698:
699: if (type == VM_PT_PMAP)
700: panic("vm_page: unable to allocate pmap page");
701:
702: return NULL;
703: }
704:
705: void
706: vm_page_free_pa(struct vm_page *page, unsigned int order)
707: {
708: assert(page != NULL);
709: assert(page->seg_index < ARRAY_SIZE(vm_page_segs));
710:
711: vm_page_seg_free(&vm_page_segs[page->seg_index], page, order);
712: }
713:
714: const char *
715: vm_page_seg_name(unsigned int seg_index)
716: {
717: /* Don't use a switch statement since segments can be aliased */
718: if (seg_index == VM_PAGE_SEG_HIGHMEM)
719: return "HIGHMEM";
720: else if (seg_index == VM_PAGE_SEG_DIRECTMAP)
721: return "DIRECTMAP";
722: else if (seg_index == VM_PAGE_SEG_DMA32)
723: return "DMA32";
724: else if (seg_index == VM_PAGE_SEG_DMA)
725: return "DMA";
726: else
727: panic("vm_page: invalid segment index");
728: }
729:
730: void
731: vm_page_info_all(void)
732: {
733: struct vm_page_seg *seg;
734: unsigned long pages;
735: unsigned int i;
736:
737: for (i = 0; i < vm_page_segs_size; i++) {
738: seg = &vm_page_segs[i];
739: pages = (unsigned long)(seg->pages_end - seg->pages);
740: printf("vm_page: %s: pages: %lu (%luM), free: %lu (%luM)\n",
741: vm_page_seg_name(i), pages, pages >> (20 - PAGE_SHIFT),
742: seg->nr_free_pages, seg->nr_free_pages >> (20 - PAGE_SHIFT));
743: }
744: }
745:
746: phys_addr_t
747: vm_page_mem_size(void)
748: {
749: phys_addr_t total;
750: unsigned int i;
751:
752: total = 0;
753:
754: for (i = 0; i < vm_page_segs_size; i++) {
755: /* XXX */
756: if (i > VM_PAGE_SEG_DIRECTMAP)
757: continue;
758:
759: total += vm_page_seg_size(&vm_page_segs[i]);
760: }
761:
762: return total;
763: }
764:
765: unsigned long
766: vm_page_mem_free(void)
767: {
768: unsigned long total;
769: unsigned int i;
770:
771: total = 0;
772:
773: for (i = 0; i < vm_page_segs_size; i++) {
774: /* XXX */
775: if (i > VM_PAGE_SEG_DIRECTMAP)
776: continue;
777:
778: total += vm_page_segs[i].nr_free_pages;
779: }
780:
781: return total;
782: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.