Minix1.1/usr/src/kernel/memory.c
/* This file contains the drivers for four special files:
* /dev/null - null device (data sink)
* /dev/mem - absolute memory
* /dev/kmem - kernel virtual memory
* /dev/ram - RAM disk
* It accepts three messages, for reading, for writing, and for
* control. All use message format m2 and with these parameters:
*
* 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 | |
* ----------------------------------------------------------------
*
*
* The file contains one entry point:
*
* mem_task: main entry when system is brought up
*
*/
#include "../h/const.h"
#include "../h/type.h"
#include "../h/callnr.h"
#include "../h/com.h"
#include "../h/error.h"
#include "const.h"
#include "type.h"
#include "proc.h"
#define NR_RAMS 4 /* number of RAM-type devices */
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. */
/*===========================================================================*
* mem_task *
*===========================================================================*/
PUBLIC mem_task()
{
/* Main program of the disk driver task. */
int r, caller, proc_nr;
extern unsigned sizes[8];
extern phys_clicks get_base();
/* Initialize this task. */
ram_origin[KMEM_DEV] = (phys_bytes) get_base() << CLICK_SHIFT;
ram_limit[KMEM_DEV] = (sizes[0] + sizes[1]) << CLICK_SHIFT;
ram_limit[MEM_DEV] = MEM_BYTES;
/* 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 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, or /dev/ram. */
int device, count;
phys_bytes mem_phys, user_phys;
struct proc *rp;
extern phys_clicks get_base();
extern phys_bytes umap();
/* 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 ? EOF : 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(EOF);
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. */
rp = proc_addr(m_ptr->PROC_NR);
user_phys = umap(rp, D, (vir_bytes) m_ptr->ADDRESS, (vir_bytes) count);
if (user_phys == 0) return(E_BAD_ADDR);
/* 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 < 0 || device >= NR_RAMS) 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);
}