18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/* nommu.c: mmu-less memory info files
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
58c2ecf20Sopenharmony_ci * Written by David Howells (dhowells@redhat.com)
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/init.h>
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/errno.h>
118c2ecf20Sopenharmony_ci#include <linux/time.h>
128c2ecf20Sopenharmony_ci#include <linux/kernel.h>
138c2ecf20Sopenharmony_ci#include <linux/string.h>
148c2ecf20Sopenharmony_ci#include <linux/mman.h>
158c2ecf20Sopenharmony_ci#include <linux/proc_fs.h>
168c2ecf20Sopenharmony_ci#include <linux/mm.h>
178c2ecf20Sopenharmony_ci#include <linux/mmzone.h>
188c2ecf20Sopenharmony_ci#include <linux/pagemap.h>
198c2ecf20Sopenharmony_ci#include <linux/swap.h>
208c2ecf20Sopenharmony_ci#include <linux/smp.h>
218c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
228c2ecf20Sopenharmony_ci#include <linux/hugetlb.h>
238c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
248c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
258c2ecf20Sopenharmony_ci#include <asm/tlb.h>
268c2ecf20Sopenharmony_ci#include <asm/div64.h>
278c2ecf20Sopenharmony_ci#include "internal.h"
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci/*
308c2ecf20Sopenharmony_ci * display a single region to a sequenced file
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_cistatic int nommu_region_show(struct seq_file *m, struct vm_region *region)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	unsigned long ino = 0;
358c2ecf20Sopenharmony_ci	struct file *file;
368c2ecf20Sopenharmony_ci	dev_t dev = 0;
378c2ecf20Sopenharmony_ci	int flags;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	flags = region->vm_flags;
408c2ecf20Sopenharmony_ci	file = region->vm_file;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	if (file) {
438c2ecf20Sopenharmony_ci		struct inode *inode = file_inode(region->vm_file);
448c2ecf20Sopenharmony_ci		dev = inode->i_sb->s_dev;
458c2ecf20Sopenharmony_ci		ino = inode->i_ino;
468c2ecf20Sopenharmony_ci	}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	seq_setwidth(m, 25 + sizeof(void *) * 6 - 1);
498c2ecf20Sopenharmony_ci	seq_printf(m,
508c2ecf20Sopenharmony_ci		   "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ",
518c2ecf20Sopenharmony_ci		   region->vm_start,
528c2ecf20Sopenharmony_ci		   region->vm_end,
538c2ecf20Sopenharmony_ci		   flags & VM_READ ? 'r' : '-',
548c2ecf20Sopenharmony_ci		   flags & VM_WRITE ? 'w' : '-',
558c2ecf20Sopenharmony_ci		   flags & VM_EXEC ? 'x' : '-',
568c2ecf20Sopenharmony_ci		   flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p',
578c2ecf20Sopenharmony_ci		   ((loff_t)region->vm_pgoff) << PAGE_SHIFT,
588c2ecf20Sopenharmony_ci		   MAJOR(dev), MINOR(dev), ino);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	if (file) {
618c2ecf20Sopenharmony_ci		seq_pad(m, ' ');
628c2ecf20Sopenharmony_ci		seq_file_path(m, file, "");
638c2ecf20Sopenharmony_ci	}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	seq_putc(m, '\n');
668c2ecf20Sopenharmony_ci	return 0;
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci/*
708c2ecf20Sopenharmony_ci * display a list of all the REGIONs the kernel knows about
718c2ecf20Sopenharmony_ci * - nommu kernels have a single flat list
728c2ecf20Sopenharmony_ci */
738c2ecf20Sopenharmony_cistatic int nommu_region_list_show(struct seq_file *m, void *_p)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	struct rb_node *p = _p;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	return nommu_region_show(m, rb_entry(p, struct vm_region, vm_rb));
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic void *nommu_region_list_start(struct seq_file *m, loff_t *_pos)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	struct rb_node *p;
838c2ecf20Sopenharmony_ci	loff_t pos = *_pos;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	down_read(&nommu_region_sem);
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	for (p = rb_first(&nommu_region_tree); p; p = rb_next(p))
888c2ecf20Sopenharmony_ci		if (pos-- == 0)
898c2ecf20Sopenharmony_ci			return p;
908c2ecf20Sopenharmony_ci	return NULL;
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic void nommu_region_list_stop(struct seq_file *m, void *v)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	up_read(&nommu_region_sem);
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic void *nommu_region_list_next(struct seq_file *m, void *v, loff_t *pos)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	(*pos)++;
1018c2ecf20Sopenharmony_ci	return rb_next((struct rb_node *) v);
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic const struct seq_operations proc_nommu_region_list_seqop = {
1058c2ecf20Sopenharmony_ci	.start	= nommu_region_list_start,
1068c2ecf20Sopenharmony_ci	.next	= nommu_region_list_next,
1078c2ecf20Sopenharmony_ci	.stop	= nommu_region_list_stop,
1088c2ecf20Sopenharmony_ci	.show	= nommu_region_list_show
1098c2ecf20Sopenharmony_ci};
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic int __init proc_nommu_init(void)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	proc_create_seq("maps", S_IRUGO, NULL, &proc_nommu_region_list_seqop);
1148c2ecf20Sopenharmony_ci	return 0;
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cifs_initcall(proc_nommu_init);
118