Minix1.1/usr/src/mm/main.c
/* This file contains the main program of the memory manager and some related
* procedures. When MINIX starts up, the kernel runs for a little while,
* initializing itself and its tasks, and then it runs MM. MM at this point
* does not know where FS is in memory and how big it is. By convention, FS
* must start at the click following MM, so MM can deduce where it starts at
* least. Later, when FS runs for the first time, FS makes a pseudo-call,
* BRK2, to tell MM how big it is. This allows MM to figure out where INIT
* is.
*
* The entry points into this file are:
* main: starts MM running
* reply: reply to a process making an MM system call
* do_brk2: pseudo-call for FS to report its size
*/
#include "../h/const.h"
#include "../h/type.h"
#include "../h/callnr.h"
#include "../h/com.h"
#include "../h/error.h"
#include "const.h"
#include "glo.h"
#include "mproc.h"
#include "param.h"
#define ENOUGH (phys_clicks) 4096 /* any # > max(FS size, INIT size) */
#define CLICK_TO_K (1024L/CLICK_SIZE) /* convert clicks to K */
PRIVATE phys_clicks tot_mem;
extern (*call_vec[])();
/*===========================================================================*
* main *
*===========================================================================*/
PUBLIC main()
{
/* Main routine of the memory manager. */
int error;
mm_init(); /* initialize memory manager tables */
/* This is MM's main loop- get work and do it, forever and forever. */
while (TRUE) {
/* Wait for message. */
get_work(); /* wait for an MM system call */
mp = &mproc[who];
/* Set some flags. */
error = OK;
dont_reply = FALSE;
err_code = -999;
/* If the call number is valid, perform the call. */
if (mm_call < 0 || mm_call >= NCALLS)
error = E_BAD_CALL;
else
error = (*call_vec[mm_call])();
/* Send the results back to the user to indicate completion. */
if (dont_reply) continue; /* no reply for EXIT and WAIT */
if (mm_call == EXEC && error == OK) continue;
reply(who, error, result2, res_ptr);
}
}
/*===========================================================================*
* get_work *
*===========================================================================*/
PRIVATE get_work()
{
/* Wait for the next message and extract useful information from it. */
if (receive(ANY, &mm_in) != OK) panic("MM receive error", NO_NUM);
who = mm_in.m_source; /* who sent the message */
if (who < HARDWARE || who >= NR_PROCS) panic("MM called by", who);
mm_call = mm_in.m_type; /* system call number */
}
/*===========================================================================*
* reply *
*===========================================================================*/
PUBLIC reply(proc_nr, result, res2, respt)
int proc_nr; /* process to reply to */
int result; /* result of the call (usually OK or error #)*/
int res2; /* secondary result */
char *respt; /* result if pointer */
{
/* Send a reply to a user process. */
register struct mproc *proc_ptr;
/* To make MM robust, check to see if destination is still alive. */
proc_ptr = &mproc[proc_nr];
if ( (proc_ptr->mp_flags&IN_USE) == 0 || (proc_ptr->mp_flags&HANGING)) return;
reply_type = result;
reply_i1 = res2;
reply_p1 = respt;
if (send(proc_nr, &mm_out) != OK) panic("MM can't reply", NO_NUM);
}
/*===========================================================================*
* mm_init *
*===========================================================================*/
PRIVATE mm_init()
{
/* Initialize the memory manager. */
extern phys_clicks get_tot_mem(), alloc_mem();
/* Find out how much memory the machine has and set up core map. MM and FS
* are part of the map. Tell the kernel.
*/
tot_mem = get_tot_mem(); /* # clicks in mem starting at absolute 0 */
mem_init(tot_mem); /* initialize tables to all physical mem */
/* Initialize MM's tables. */
mproc[MM_PROC_NR].mp_flags |= IN_USE;
mproc[FS_PROC_NR].mp_flags |= IN_USE;
mproc[INIT_PROC_NR].mp_flags |= IN_USE;
procs_in_use = 3;
/* Set stack limit, which is checked on every procedure call. */
}
/*===========================================================================*
* do_brk2 *
*===========================================================================*/
PUBLIC do_brk2()
{
/* This "call" is made once by FS during system initialization and then never
* again by anyone. It contains the origin and size of INIT, and the combined
* size of the 1536 bytes of unused mem, MINIX and RAM disk.
* m1_i1 = size of INIT text in clicks
* m1_i2 = size of INIT data in clicks
* m1_i3 = number of bytes for MINIX + RAM DISK
* m1_p1 = origin of INIT in clicks
*/
int mem1, mem2, mem3;
register struct mproc *rmp;
phys_clicks init_org, init_clicks, ram_base, ram_clicks, tot_clicks;
phys_clicks init_text_clicks, init_data_clicks;
if (who != FS_PROC_NR) return(EPERM); /* only FS make do BRK2 */
/* Remove the memory used by MINIX and RAM disk from the memory map. */
init_text_clicks = mm_in.m1_i1; /* size of INIT in clicks */
init_data_clicks = mm_in.m1_i2; /* size of INIT in clicks */
tot_clicks = mm_in.m1_i3; /* total size of MINIX + RAM disk */
init_org = (phys_clicks) mm_in.m1_p1; /* addr where INIT begins in memory */
init_clicks = init_text_clicks + init_data_clicks;
ram_base = init_org + init_clicks; /* start of RAM disk */
ram_clicks = tot_clicks - ram_base; /* size of RAM disk */
alloc_mem(tot_clicks); /* remove RAM disk from map */
/* Print memory information. */
mem1 = tot_mem/CLICK_TO_K;
mem2 = (ram_base + 512/CLICK_SIZE)/CLICK_TO_K; /* MINIX, rounded */
mem3 = ram_clicks/CLICK_TO_K;
printf("%c 8%c~0",033, 033); /* go to top of screen and clear screen */
printf("Memory size = %dK ", mem1);
printf("MINIX = %dK ", mem2);
printf("RAM disk = %dK ", mem3);
printf("Available = %dK\n\n", mem1 - mem2 - mem3);
if (mem1 - mem2 - mem3 < 32) {
printf("\nNot enough memory to run MINIX\n\n", NO_NUM);
sys_abort();
}
/* Initialize INIT's table entry. */
rmp = &mproc[INIT_PROC_NR];
rmp->mp_seg[T].mem_phys = init_org;
rmp->mp_seg[T].mem_len = init_text_clicks;
rmp->mp_seg[D].mem_phys = init_org + init_text_clicks;
rmp->mp_seg[D].mem_len = init_data_clicks;
rmp->mp_seg[S].mem_vir = init_clicks;
rmp->mp_seg[S].mem_phys = init_org + init_clicks;
if (init_text_clicks != 0) rmp->mp_flags |= SEPARATE;
return(OK);
}
/*===========================================================================*
* set_map *
*===========================================================================*/
PRIVATE set_map(proc_nr, base, clicks)
int proc_nr; /* whose map to set? */
phys_clicks base; /* where in memory does the process start? */
phys_clicks clicks; /* total size in clicks (sep I & D not used) */
{
/* Set up the memory map as part of the system initialization. */
register struct mproc *rmp;
vir_clicks vclicks;
rmp = &mproc[proc_nr];
vclicks = (vir_clicks) clicks;
rmp->mp_seg[T].mem_vir = 0;
rmp->mp_seg[T].mem_len = 0;
rmp->mp_seg[T].mem_phys = base;
rmp->mp_seg[D].mem_vir = 0;
rmp->mp_seg[D].mem_len = vclicks;
rmp->mp_seg[D].mem_phys = base;
rmp->mp_seg[S].mem_vir = vclicks;
rmp->mp_seg[S].mem_len = 0;
rmp->mp_seg[S].mem_phys = base + vclicks;
sys_newmap(proc_nr, rmp->mp_seg);
}