/*
 * Copyright (C) 2000-2002 ASANO Masahiro
 */

#include "def.h"

#define __KERNEL__
#include <linux/mm.h>

#include "flags_mm.h"

void
prhead_page()
{
#ifndef _page_has_zone
	/* >= 2.4.19 and Red Hat 7.3 kerenel */
#if CONFIG_HIGHMEM
	mprintf(SPTR" "SPTR"    INDEX CNT "SPTR" "SPTR" FLAGS\n",
		"ADDR", "MAPPING", "BUFFERS", "VIRTUAL");
#else
	mprintf(SPTR" "SPTR"    INDEX CNT "SPTR" FLAGS\n",
		"ADDR", "MAPPING", "BUFFERS");
#endif /*CONFIG_HIGHMEM*/
#else
	/* <= 2.4.18 */
	mprintf(SPTR" "SPTR"    INDEX CNT "SPTR" "SPTR" "SPTR" FLAGS\n",
		"ADDR", "MAPPING", "BUFFERS", "VIRTUAL", "ZONE");
#endif /*!_page_has_zone*/
}

int sizeof_page = sizeof(struct page);

addr_t
print_page(addr, aflag)
	addr_t addr;
	int aflag;
{
	struct page pg;

	mprintf(FPTR " ", addr);
	if (addr == 0) {
		mprintf("\n");
		return 0;
	}
	memread(addr, sizeof(pg), &pg, "page");

	mprintf(FPTR " %8lx %3x", pg.mapping, pg.index, ATOMIC_READ(pg.count));
	mprintf(" " FPTR, pg.buffers);
#if SUBLEVEL<18
	mprintf(" " FPTR " " FPTR, pg.virtual, pg.zone);
#else
#ifdef CONFIG_HIGHMEM
	mprintf(" " FPTR, pg.virtual);
#endif
#endif
	mprintbit(pgflags, pg.flags);
	mprintf("\n");
	if (aflag)
		return (addr_t)pg.list.next - OFFSET(struct page, list);
	return (addr_t)pg.next_hash;
}

void
prhead_vm_area_struct()
{
	mprintf(SPTR " " SPTR " " SPTR " " SPTR "  FLAGS\n",
		"ADDR", "START", "END", "FILE");
}

addr_t
print_vm_area_struct(addr, full)
	addr_t addr;
{
	struct vm_area_struct vma;
	static const struct bitname vmflags[] = {
		{ VM_READ,	"R" },
		{ VM_WRITE,	"W" },
		{ VM_EXEC,	"X" },
		{ VM_SHARED,	"S" },

		{ VM_MAYREAD,	"mayR" },
		{ VM_MAYWRITE,	"mayW" },
		{ VM_MAYEXEC,	"mayX" },
		{ VM_MAYSHARE,	"mayS" },

		{ VM_GROWSDOWN,	"growsdown" },
		{ VM_GROWSUP,	"growsup" },
		{ VM_SHM,	"shm" },
		{ VM_DENYWRITE,	"denywrite" },

		{ VM_EXECUTABLE,"executable" },
		{ VM_LOCKED,	"locked" },
		{ VM_IO,	"io" },

		{ VM_SEQ_READ,	"seq_read" },
		{ VM_RAND_READ,	"rand_read" },

		{ VM_DONTCOPY,	"dontcopy" },
		{ VM_DONTEXPAND,"dontexpand" },
		{ VM_RESERVED,	"reserved" },
		{ 0,		NULL }
	};

	memread(addr, sizeof(vma), &vma, "vm_area_struct");

	if (!full) {
		mprintf(FPTR " " FPTR " " FPTR " " FPTR " ",
			addr, vma.vm_start, vma.vm_end, vma.vm_file);
		mprintbit(vmflags, vma.vm_flags);
		mprintf("\n");
		return (addr_t)vma.vm_next;
	}
	mprintf("addr:           " FPTR "\n", addr);

	mprintf("vm_mm:          " FPTR "\n", vma.vm_mm);
	mprintf("vm_start:       " FPTR "\n", vma.vm_start);
	mprintf("vm_end:         " FPTR "\n", vma.vm_end);
	mprintf("vm_next:        " FPTR "\n", vma.vm_next);
	mprintf("vm_flags:      ");
	mprintbit(vmflags, vma.vm_flags);
	mprintf("\n");
#if SUBLEVEL<10
	mprintf("vm_avl_height:  %8x\n",  vma.vm_avl_height);
	mprintf("vm_avl_left:    " FPTR "\n", vma.vm_avl_left);
	mprintf("vm_avl_right:   " FPTR "\n", vma.vm_avl_right);
#endif
	mprintf("vm_next_share:  " FPTR "\n", vma.vm_next_share);
	mprintf("vm_ops:         " FPTR "\n", vma.vm_ops);
	mprintf("vm_pgoff:       " FPTR "\n", vma.vm_pgoff);
	mprintf("vm_file:        " FPTR "\n", vma.vm_file);
	mprintf("vm_private_data:" FPTR "\n", vma.vm_private_data);
	return (addr_t)vma.vm_next;
}

void
print_gfp(gfp)
	int gfp;
{
	static const struct bitname gfpbit[] = {
		{ __GFP_DMA,		"dma" },
		{ __GFP_HIGHMEM,	"highmem" },
		{ __GFP_WAIT,		"wait" },
		{ __GFP_HIGH,		"high" },
		{ __GFP_IO,		"io" },
#ifdef __GFP_HIGHIO
		{ __GFP_HIGHIO,		"highio" },
#endif
#ifdef __GFP_VM
		{ __GFP_VM,		"vm" },
#endif
#ifdef __GFP_FAIL
		{ __GFP_FAIL,		"fail" },
#endif
#ifdef __GFP_FS
		{ __GFP_FS,		"fs" },
#endif
		{ 0,			NULL }
	};
	const char *p = NULL;

	mprintbit(gfpbit, gfp);
	switch (gfp) {
#ifdef GFP_BOUNCE
	case GFP_BOUNCE:	p = "BOUNCE";	break;
#endif
#ifdef GFP_BUFFER
	case GFP_BUFFER:	p = "BUFFER";	break;
#endif
#ifdef GFP_NOHIGHIO
	case GFP_NOHIGHIO:	p = "NOHIGHIO";	break;
#endif
#ifdef GFP_NOIO
	case GFP_NOIO:		p = "NOIO";	break;
#endif
#ifdef GFP_NOFS
	case GFP_NOFS:		p = "NOFS";	break;
#endif
	case GFP_ATOMIC:	p = "ATOMIC";	break;
	case GFP_USER:		p = "USER";	break;
#if GFP_USER != GFP_HIGHUSER
	case GFP_HIGHUSER:	p = "HIGHUSER";	break;
#endif
	case GFP_KERNEL:	p = "KERNEL";	break;
#if GFP_KERNEL != GFP_NFS
	case GFP_NFS:		p = "NFS";	break;
#endif
#if GFP_KSWAPD != GFP_USER
	case GFP_KSWAPD:	p = "KSWAPD";	break;
#endif
#ifdef GFP_DMA
	case GFP_DMA:		p = "DMA";	break;
#endif
	}
	if (p) {
		mprintf("  (GFP_%s)\n", p);
	} else {
		mprintf("\n");
	}
}
