Minix1.5/kernel/memory.c

Compare this file to the similar file:
Show the results in this format:

/* This file contains the drivers for the following special files:
 *     /dev/null	- null device (data sink)
 *     /dev/mem		- absolute memory
 *     /dev/kmem	- kernel virtual memory
 *     /dev/ram		- RAM disk
 *     /dev/port	- i/o ports ((CHIP == INTEL) only)
 *
 * The driver supports the following operations (using message format m2):
 *
 *    m_type      DEVICE    PROC_NR     COUNT    POSITION  ADRRESS
 * ----------------------------------------------------------------
 * |  DISK_READ | device  | proc nr |  bytes  |  offset | buf ptr |
 * |------------+---------+---------+---------+---------+---------|
 * | DISK_WRITE | device  | proc nr |  bytes  |  offset | buf ptr |
 * |------------+---------+---------+---------+---------+---------|
 * | DISK_IOCTL | device  |         |  blocks | ram org |         |
 * ----------------------------------------------------------------
 * |SCATTERED_IO| device  | proc nr | requests|         | iov ptr |
 * ----------------------------------------------------------------
 *  
 *
 * The file contains one entry point:
 *
 *   mem_task:	main entry when system is brought up
 *
 */

#include "kernel.h"
#include <minix/callnr.h>
#include <minix/com.h>

#ifdef PORT_DEV
#define NR_RAMS            5	/* number of RAM-type devices */
#else
#define NR_RAMS            4
#endif
PRIVATE message mess;		/* message buffer */
PRIVATE phys_bytes ram_origin[NR_RAMS];	/* origin of each RAM disk  */
PRIVATE phys_bytes ram_limit[NR_RAMS];	/* limit of RAM disk per minor dev. */

FORWARD int do_mem();
FORWARD int do_setup();

/*===========================================================================*
 *				mem_task				     * 
 *===========================================================================*/
PUBLIC void mem_task()
{
/* Main program of the memory task. */

  int r, caller, proc_nr;

  /* Initialize this task. */
  ram_origin[KMEM_DEV] = numap(SYSTASK, (vir_bytes) 0, (vir_bytes) 1);
  ram_limit[KMEM_DEV] = ((phys_bytes) sizes[1] << CLICK_SHIFT) +
                        ram_origin[KMEM_DEV];
#if (CHIP == INTEL)
  if (!protected_mode)
	ram_limit[MEM_DEV] = 0x100000;	/* above 1M em_xfer word count fails */
  else
	ram_limit[MEM_DEV] = 0x1000000;	/* above 16M not mapped on 386 */
  ram_limit[PORT_DEV] = 0x10000;
#else
#if (CHIP == M68000)
  ram_limit[MEM_DEV] = MEM_BYTES;
#else
#error /* memory limit not set up */
#endif
#endif

  /* Here is the main loop of the memory task.  It waits for a message, carries
   * it out, and sends a reply.
   */
  while (TRUE) {
	/* First wait for a request to read or write. */
	receive(ANY, &mess);
	if (mess.m_source < 0)
		panic("mem task got message from ", mess.m_source);
	caller = mess.m_source;
	proc_nr = mess.PROC_NR;

	/* Now carry out the work.  It depends on the opcode. */
	switch(mess.m_type) {
	    case DISK_READ:	r = do_mem(&mess);	break;
	    case DISK_WRITE:	r = do_mem(&mess);	break;
	    case SCATTERED_IO:	r = do_vrdwt(&mess, do_mem); break;
	    case DISK_IOCTL:	r = do_setup(&mess);	break;
	    default:		r = EINVAL;		break;
	}

	/* Finally, prepare and send the reply message. */
	mess.m_type = TASK_REPLY;
	mess.REP_PROC_NR = proc_nr;
	mess.REP_STATUS = r;
	send(caller, &mess);
  }
}


/*===========================================================================*
 *				do_mem					     * 
 *===========================================================================*/
PRIVATE int do_mem(m_ptr)
register message *m_ptr;	/* pointer to read or write message */
{
/* Read or write /dev/null, /dev/mem, /dev/kmem, /dev/ram or /dev/port. */

  int device, count, endport, port, portval;
  phys_bytes mem_phys, user_phys;

  /* Get minor device number and check for /dev/null. */
  device = m_ptr->DEVICE;
  if (device < 0 || device >= NR_RAMS) return(ENXIO);	/* bad minor device */
  if (device==NULL_DEV) return(m_ptr->m_type == DISK_READ ? 0 : m_ptr->COUNT);

  /* Set up 'mem_phys' for /dev/mem, /dev/kmem, or /dev/ram. */
  if (m_ptr->POSITION < 0) return(ENXIO);
  mem_phys = ram_origin[device] + m_ptr->POSITION;
  if (mem_phys >= ram_limit[device]) return(0);
  count = m_ptr->COUNT;
  if(mem_phys + count > ram_limit[device]) count = ram_limit[device] - mem_phys;

  /* Determine address where data is to go or to come from. */
  user_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS,
		    (vir_bytes) count);
  if (user_phys == 0) return(E_BAD_ADDR);

#ifdef PORT_DEV
  /* Do special case of /dev/port. */
  if (device == PORT_DEV) {
	port = mem_phys;
	mem_phys = umap(proc_ptr, D, (vir_bytes) &portval, (vir_bytes) 1);
	for (endport = port + count; port != endport; ++port) {
		if (m_ptr->m_type == DISK_READ) {
			portval = in_byte(port);
			phys_copy(mem_phys, user_phys++, (phys_bytes) 1);
		} else {
			phys_copy(user_phys++, mem_phys, (phys_bytes) 1);
			out_byte(port, portval);
		}
	}
	return(count);
  }
#endif

  /* Copy the data. */
  if (m_ptr->m_type == DISK_READ)
	phys_copy(mem_phys, user_phys, (long) count);
  else
	phys_copy(user_phys, mem_phys, (long) count);
  return(count);
}


/*===========================================================================*
 *				do_setup				     * 
 *===========================================================================*/
PRIVATE int do_setup(m_ptr)
message *m_ptr;			/* pointer to read or write message */
{
/* Set parameters for one of the disk RAMs. */

  int device;

  device = m_ptr->DEVICE;
  if (device != RAM_DEV) return(ENXIO);	/* bad minor device */
  ram_origin[device] = m_ptr->POSITION;
  ram_limit[device] = m_ptr->POSITION + (long) m_ptr->COUNT * BLOCK_SIZE;
  return(OK);
}