/* $Id: init.c,v 1.12 1998/09/10 15:11:21 bjornw Exp $
 *
 *  linux/arch/m68k/mm/init.c
 *
 *  Copyright (C) 1995  Hamish Macdonald
 */

#include <linux/config.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/types.h>
#ifdef CONFIG_BLK_DEV_RAM
#include <linux/blk.h>
#endif

#include <asm/setup.h>
#include <asm/segment.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/system.h>

#ifndef PAGE_OFFSET
#define PAGE_OFFSET 0
#endif

extern void die_if_kernel(char *,struct pt_regs *,long);
extern void show_net_buffers(void);

/*
 * BAD_PAGE is the page that is used for page faults when linux
 * is out-of-memory. Older versions of linux just did a
 * do_exit(), but using this instead means there is less risk
 * for a process dying in kernel mode, possibly leaving a inode
 * unused etc..
 *
 * BAD_PAGETABLE is the accompanying page-table: it is initialized
 * to point to BAD_PAGE entries.
 *
 * ZERO_PAGE is a special page that is used for zero-initialized
 * data and COW.
 */
static unsigned long empty_bad_page_table;

static unsigned long empty_bad_page;

unsigned long empty_zero_page;

void show_mem(void)
{
    unsigned long i;
    int free = 0, total = 0, reserved = 0, nonshared = 0, shared = 0;

    printk("\nMem-info:\n");
    show_free_areas();
    printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
    i = high_memory >> PAGE_SHIFT;
    while (i-- > 0) {
	total++;
	if (PageReserved(mem_map+i))
	    reserved++;
	else if (!mem_map[i].count)
	    free++;
	else if (mem_map[i].count == 1)
	    nonshared++;
	else
	    shared += mem_map[i].count-1;
    }
    printk("%d pages of RAM\n",total);
    printk("%d free pages\n",free);
    printk("%d reserved pages\n",reserved);
    printk("%d pages nonshared\n",nonshared);
    printk("%d pages shared\n",shared);
    show_buffers();
#ifdef CONFIG_NET
    show_net_buffers();
#endif
}

extern unsigned long free_area_init(unsigned long, unsigned long);

/*
 * paging_init() continues the virtual memory environment setup which
 * was begun by the code in arch/head.S.
 * The parameters are pointers to where to stick the starting and ending
 * addresses  of available kernel virtual memory.
 */
unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
{
	int chunk;
	/* pointer to page table for kernel stacks */
	extern unsigned long availmem;
      
	/*
	 * virtual address after end of kernel
	 * "availmem" is setup by the code in head.S.
	 */
	/*start_mem = availmem;*/

#if 0
	printk("start_mem is %#lx\n", start_mem);
	printk("virtual_end is %#lx\n", end_mem);
#endif

        /*
	 * initialize the bad page table and bad page to point
	 * to a couple of allocated pages
	 */
	empty_bad_page_table = start_mem;
	start_mem += PAGE_SIZE;
	empty_bad_page = start_mem;
	start_mem += PAGE_SIZE;
	empty_zero_page = start_mem;
	start_mem += PAGE_SIZE;
	memset((void *)empty_zero_page, 0, PAGE_SIZE);

	/*
	 * Set up SFC/DFC registers (user data space)
	 */
	set_fs (USER_DS); /* E: NOTE! set_fs() is an empty function */

#if 0
	printk("free_area_init -> start_mem is %#lx\n", start_mem);
	printk("                  virtual_end is %#lx\n", end_mem);
#endif

	return PAGE_ALIGN(free_area_init (start_mem, end_mem));
}

void mem_init(unsigned long start_mem, unsigned long end_mem)
{
	int codepages = 0;
	int datapages = 0;
	unsigned long tmp;
	extern int etext, _end, _data_end, _bss_start, _Sdata;
	unsigned long len = end_mem-(unsigned long)&_Sdata;

	printk("Mem_init: start=%lx, end=%lx\n", start_mem, end_mem);
#if 0
	printk("\nKernel data:\n");
	printk("Start textsegment: 0xc0000500\n");
	printk("Stop  textsegment: 0x%lx\n",(unsigned long)&etext);
	printk("Start datasegment: 0x%lx\n",(unsigned long)&_Sdata);
	printk("Stop  datasegment: 0x%lx\n",(unsigned long)&_data_end);
	printk("Start bss-segment: 0x%lx\n",(unsigned long)&_bss_start);
	printk("Stop  bss-segment: 0x%lx\n\n",(unsigned long)&_end);
#endif
	end_mem &= PAGE_MASK;
	high_memory = end_mem;

	start_mem = PAGE_ALIGN(start_mem);
	while (start_mem < high_memory) {
		clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags);
		start_mem += PAGE_SIZE;
	}

	for (tmp = PAGE_OFFSET; tmp < end_mem ; tmp += PAGE_SIZE) {
#if 0
	        if (temp >= MAX_DMA_ADDRESS)
		        clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags);
#endif
		if (PageReserved(mem_map+MAP_NR(tmp))) {
		        if (tmp < (unsigned long)&etext)
			        codepages++;
			else
				datapages++;
			continue;
		}
		mem_map[MAP_NR(tmp)].count = 1;
#ifdef CONFIG_BLK_DEV_INITRD
		if (!initrd_start ||
		    (tmp < (initrd_start & PAGE_MASK) || tmp >= initrd_end))
#endif
			free_page(tmp);
	}
	/*	codepages = (&_etext - &_Stext) >> PAGE_SHIFT;*/

	tmp = nr_free_pages << PAGE_SHIFT;
	
	printk("Memory: %luk/%luk available (%dk kernel code, %dk data)\n",
	       tmp >> 10,
	       len >> 10,
	       codepages << (PAGE_SHIFT-10),
	       datapages << (PAGE_SHIFT-10));
}

void si_meminfo(struct sysinfo *val)
{
    unsigned long i;

    i = (high_memory - PAGE_OFFSET) >> PAGE_SHIFT;
    val->totalram = 0;
    val->sharedram = 0;
    val->freeram = nr_free_pages << PAGE_SHIFT;
    val->bufferram = buffermem;
    while (i-- > 0) {
	if (PageReserved(mem_map+i))
	    continue;
	val->totalram++;
	if (!mem_map[i].count)
	    continue;
	val->sharedram += mem_map[i].count-1;
    }
    val->totalram <<= PAGE_SHIFT;
    val->sharedram <<= PAGE_SHIFT;
    return;
}

