Minix1.5/fs/main.c
/* This file contains the main program of the File System. It consists of
* a loop that gets messages requesting work, carries out the work, and sends
* replies.
*
* The entry points into this file are
* main: main program of the File System
* reply: send a reply to a process after the requested work is done
*/
#include "fs.h"
#include <minix/callnr.h>
#include <minix/com.h>
#include <minix/boot.h>
#include "buf.h"
#include "file.h"
#include "fproc.h"
#include "inode.h"
#include "param.h"
#include "super.h"
#if FASTLOAD
#include "dev.h"
#endif
#define M64K 0xFFFF0000L /* 16 bit mask for DMA check */
#define MAX_RAM 16384 /* maximum RAM disk size in blocks */
#define RAM_IMAGE (dev_t)0x303 /* major-minor dev where root image is kept */
#define DEMO_RAM_OFFSET 200 /* location of RAM image on demo diskette */
FORWARD void buf_pool();
FORWARD void fs_init();
FORWARD void get_boot_parameters();
FORWARD void get_work();
FORWARD dev_t load_ram();
FORWARD void load_super();
#if ASKDEV
FORWARD int askdev();
#endif
#if FASTLOAD
FORWARD void fastload();
FORWARD int lastused();
#endif
#if (CHIP == INTEL)
FORWARD phys_bytes get_physbase();
#endif
/*===========================================================================*
* main *
*===========================================================================*/
PUBLIC void main()
{
/* This is the main program of the file system. The main loop consists of
* three major activities: getting new work, processing the work, and sending
* the reply. This loop never terminates as long as the file system runs.
*/
int error;
fs_init();
/* This is the main loop that gets work, processes it, and sends replies. */
while (TRUE) {
get_work(); /* sets who and fs_call */
fp = &fproc[who]; /* pointer to proc table struct */
super_user = (fp->fp_effuid == SU_UID ? TRUE : FALSE); /* su? */
dont_reply = FALSE; /* in other words, do reply is default */
/* Call the internal function that does the work. */
if (fs_call < 0 || fs_call >= NCALLS)
error = EBADCALL;
else
error = (*call_vector[fs_call])();
/* Copy the results back to the user and send reply. */
if (dont_reply) continue;
reply(who, error);
if (rdahed_inode != NIL_INODE) read_ahead(); /* do block read ahead */
}
}
/*===========================================================================*
* get_work *
*===========================================================================*/
PRIVATE void get_work()
{
/* Normally wait for new input. However, if 'reviving' is
* nonzero, a suspended process must be awakened.
*/
register struct fproc *rp;
if (reviving != 0) {
/* Revive a suspended process. */
for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++)
if (rp->fp_revived == REVIVING) {
who = (int)(rp - fproc);
fs_call = rp->fp_fd & BYTE;
fd = (rp->fp_fd >>8) & BYTE;
buffer = rp->fp_buffer;
nbytes = rp->fp_nbytes;
rp->fp_suspended = NOT_SUSPENDED; /*no longer hanging*/
rp->fp_revived = NOT_REVIVING;
reviving--;
return;
}
panic("get_work couldn't revive anyone", NO_NUM);
}
/* Normal case. No one to revive. */
if (receive(ANY, &m) != OK) panic("fs receive error", NO_NUM);
who = m.m_source;
fs_call = m.m_type;
}
/*===========================================================================*
* reply *
*===========================================================================*/
PUBLIC void reply(whom, result)
int whom; /* process to reply to */
int result; /* result of the call (usually OK or error #) */
{
/* Send a reply to a user process. It may fail (if the process has just
* been killed by a signal), so don't check the return code. If the send
* fails, just ignore it.
*/
reply_type = result;
send(whom, &m1);
}
/*===========================================================================*
* fs_init *
*===========================================================================*/
PRIVATE void fs_init()
{
/* Initialize global variables, tables, etc. */
register struct inode *rip;
int i;
dev_t d; /* device to fetch the superblock from */
buf_pool(); /* initialize buffer pool */
get_boot_parameters();
d = load_ram(); /* init RAM disk, load if it is root */
load_super(d); /* Load super block for root device */
/* Initialize the 'fproc' fields for process 0 and process 2. */
for (i = 0; i < 3; i+= 2) {
fp = &fproc[i];
rip = get_inode(ROOT_DEV, ROOT_INODE);
fp->fp_rootdir = rip;
dup_inode(rip);
fp->fp_workdir = rip;
fp->fp_realuid = (uid_t) SYS_UID;
fp->fp_effuid = (uid_t) SYS_UID;
fp->fp_realgid = (gid_t) SYS_GID;
fp->fp_effgid = (gid_t) SYS_GID;
fp->fp_umask = ~0;
}
/* Certain relations must hold for the file system to work at all. */
if (ZONE_NUM_SIZE != 2) panic("ZONE_NUM_SIZE != 2", NO_NUM);
if (SUPER_SIZE > BLOCK_SIZE) panic("SUPER_SIZE > BLOCK_SIZE", NO_NUM);
if(BLOCK_SIZE % INODE_SIZE != 0)panic("BLOCK_SIZE % INODE_SIZE != 0",NO_NUM);
if (OPEN_MAX > 127) panic("OPEN_MAX > 127", NO_NUM);
if (NR_BUFS < 6) panic("NR_BUFS < 6", NO_NUM);
if (sizeof(d_inode) != 32) panic("inode size != 32", NO_NUM);
}
/*===========================================================================*
* buf_pool *
*===========================================================================*/
PRIVATE void buf_pool()
{
/* Initialize the buffer pool. On the IBM PC, the hardware DMA chip is
* not able to cross 64K boundaries, so any buffer that happens to lie
* across such a boundary is not used. This is not very elegant, but all
* the alternative solutions are as bad, if not worse. The fault lies with
* the PC hardware.
*/
register struct buf *bp;
vir_bytes low_off, high_off; /* only used on INTEL chips */
phys_bytes org;
bufs_in_use = 0;
front = &buf[0];
rear = &buf[NR_BUFS - 1];
for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) {
bp->b_blocknr = NO_BLOCK;
bp->b_dev = NO_DEV;
bp->b_next = bp + 1;
bp->b_prev = bp - 1;
}
buf[0].b_prev = NIL_BUF;
buf[NR_BUFS - 1].b_next = NIL_BUF;
/* Delete any buffers that span a 64K boundary, by marking them as used. */
#if (CHIP == INTEL)
for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) {
org = get_physbase(); /* phys addr where FS is */
low_off = (vir_bytes) bp->b_data;
high_off = low_off + BLOCK_SIZE - 1;
if (((org + low_off) & M64K) != ((org + high_off) & M64K)) {
++bp->b_count; /* it was 0, by static initialization */
++bufs_in_use;
}
}
#endif
for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) bp->b_hash = bp->b_next;
buf_hash[NO_BLOCK & (NR_BUF_HASH - 1)] = front;
}
/*===========================================================================*
* load_ram *
*===========================================================================*/
PRIVATE dev_t load_ram()
{
/* If the root device is the RAM disk, copy the entire root image device
* block-by-block to a RAM disk with the same size as the image.
* Otherwise, just allocate a RAM disk with size given in the boot parameters.
*/
register struct buf *bp, *bp1;
int count;
long k_loaded;
struct super_block *sp;
block_nr ram_offset = 0; /* block offset of RAM image on demo diskette*/
block_nr i, b;
dev_t root_device; /* really the root image device */
dev_t super_dev; /* device to get superblock from */
phys_clicks ram_clicks, init_org, init_text_clicks, init_data_clicks;
/* Get size of INIT by reading block on diskette where 'build' put it. */
init_org = data_org[INFO];
init_text_clicks = data_org[INFO + 1];
init_data_clicks = data_org[INFO + 2];
/* Print ATARI copyright message. */
#if (MACHINE == ATARI)
printf("Booting MINIX 1.5. Copyright 1990 Prentice-Hall, Inc.\n");
#endif
/* If the root device is specified in the boot parameters, use it. */
if (ROOT_DEV != DEV_RAM) {
count = boot_parameters.bp_ramsize;
super_dev = ROOT_DEV; /* get superblock directly from root device */
goto got_root_dev; /* kludge to avoid excessive indent/diffs */
} else {
super_dev = DEV_RAM; /* get superblock from RAM disk */
}
/* Get size of RAM disk by reading root file system's super block.
* First read block 0 from the floppy. If this is a valid file system, use
* it as the root image, otherwise try the hard disk (RAM_IMAGE).
*/
#if ASKDEV
root_device = (dev_t)askdev();
if (root_device == 0)
#endif
#if DEMO
/* If this file is compiled with -DDEMO=1, RAM image is at DEMO_RAM_OFFSET */
ram_offset = DEMO_RAM_OFFSET;
#endif
root_device = BOOT_DEV; /* get super block; try floppy disk first */
bp = get_block(root_device, SUPER_BLOCK + ram_offset, NORMAL);
copy(super_block, bp->b_data, SUPER_SIZE);
sp = &super_block[0];
if (sp->s_magic != SUPER_MAGIC) {
put_block(bp, FULL_DATA_BLOCK);
root_device = RAM_IMAGE;
bp = get_block(root_device, SUPER_BLOCK, NORMAL); /* get super block*/
copy(super_block, bp->b_data, SUPER_SIZE);
sp = &super_block[0];
if (sp->s_magic != SUPER_MAGIC)
panic("Invalid root file system", NO_NUM);
}
count = sp->s_nzones << sp->s_log_zone_size; /* # blocks on root dev */
put_block(bp, FULL_DATA_BLOCK);
got_root_dev:
if (count > MAX_RAM) panic("RAM disk is too big. # blocks = ", count);
ram_clicks = count * (BLOCK_SIZE/CLICK_SIZE);
/* Tell MM the origin and size of INIT, and the amount of memory used for the
* system plus RAM disk combined, so it can remove all of it from the map.
*/
m1.m_type = BRK2;
m1.m1_i1 = init_text_clicks;
m1.m1_i2 = init_data_clicks;
m1.m1_i3 = init_org + init_text_clicks + init_data_clicks + ram_clicks;
#if (MACHINE == ATARI)
m1.m1_p1 = (char *) (int) init_org; /* bug in Alcyon 4.14 C */
#else
m1.m1_p1 = (char *) init_org; /* other compilers */
#endif
if (sendrec(MM_PROC_NR, &m1) != OK) panic("FS Can't report to MM", NO_NUM);
/* Tell RAM driver where RAM disk is and how big it is. The BRK2 call has
* filled in the m1.POSITION field.
*/
m1.m_type = DISK_IOCTL;
m1.DEVICE = RAM_DEV;
m1.COUNT = count;
if (sendrec(MEM, &m1) != OK) panic("Can't report size to MEM", NO_NUM);
#if (CHIP == INTEL)
/* Say if we are running in real mode or protected mode.
* 'bp_processor' is re-used to mean 'protected_mode'.
*/
printf("Executing in %s mode\n\n",
boot_parameters.bp_processor ? "protected" : "real");
#endif
/* If the root device is not the RAM disk, it doesn't need loading. */
if (ROOT_DEV != DEV_RAM) return(super_dev); /* ROOT_DEV is a macro */
/* Copy the blocks one at a time from the root diskette to the RAM */
#if FASTLOAD
fastload(root_device, (char *) m1.POSITION); /* assumes 32 bit pointers */
#else
printf("Loading RAM disk. Loaded: 0K ");
inode[0].i_mode = I_BLOCK_SPECIAL; /* temp inode for rahead */
inode[0].i_size = MAX_P_LONG;
inode[0].i_dev = inode[0].i_zone[0] = root_device;
for (i = 0; i < count; i++) {
b = i + ram_offset; /* true block number */
bp = rahead(&inode[0], (block_nr) b, (off_t)BLOCK_SIZE*b, BLOCK_SIZE);
bp1 = get_block(ROOT_DEV, i, NO_READ);
copy(bp1->b_data, bp->b_data, BLOCK_SIZE);
bp1->b_dirt = DIRTY;
put_block(bp, I_MAP_BLOCK);
put_block(bp1, I_MAP_BLOCK);
k_loaded = ( (long) i * BLOCK_SIZE)/1024L; /* K loaded so far */
if (k_loaded % 5 == 0) printf("\b\b\b\b\b\b%4DK %c", k_loaded, 0);
}
#endif /* FASTLOAD */
if ( ((root_device ^ DEV_FD0) & ~BYTE) == 0 )
printf("\rRAM disk loaded. Please remove root diskette. \n\n");
else
printf("\rRAM disk loaded. \n\n");
return(super_dev);
}
/*===========================================================================*
* load_super *
*===========================================================================*/
PRIVATE void load_super(super_dev)
dev_t super_dev; /* place to get superblock from */
{
register struct super_block *sp;
register struct inode *rip;
/* Initialize the super_block table. */
for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++)
sp->s_dev = NO_DEV;
/* Read in super_block for the root file system. */
sp = &super_block[0];
sp->s_dev = super_dev;
rw_super(sp,READING);
rip = get_inode(super_dev, ROOT_INODE); /* inode for root dir */
/* Check super_block for consistency (is it the right diskette?). */
if ( (rip->i_mode & I_TYPE) != I_DIRECTORY || rip->i_nlinks < 3 ||
sp->s_magic != SUPER_MAGIC)
panic("Root file system corrupted. Possibly wrong diskette.", NO_NUM);
sp->s_imount = rip;
dup_inode(rip);
sp->s_isup = rip;
sp->s_rd_only = 0;
if (load_bit_maps(super_dev) != OK)
panic("init: can't load root bit maps", NO_NUM);
return;
}
#if ASKDEV
/*===========================================================================*
* askdev *
*===========================================================================*/
PRIVATE askdev()
{
char line[80];
register char *p;
register min, maj, c, n;
printf("Insert ROOT diskette and hit RETURN (or specify bootdev) %c", 0);
m.m_type = TTY_READ;
m.TTY_LINE = 0;
m.PROC_NR = FS_PROC_NR;
m.ADDRESS = line;
m.COUNT = sizeof(line);
if (sendrec(TTY, &m) != OK)
return(0);
for (;;) {
if (m.REP_PROC_NR != FS_PROC_NR)
return(-1);
if (m.REP_STATUS != SUSPEND)
break;
receive(TTY, &m);
}
if ((n = m.REP_STATUS) <= 0)
return(0);
p = line;
for (maj = 0;;) {
if (--n < 0)
return(0);
c = *p++;
if (c == ',')
break;
if (c < '0' || c > '9')
return(0);
maj = maj * 10 + c - '0';
}
for (min = 0;;) {
if (--n < 0)
return(0);
c = *p++;
if (c == '\n')
break;
if (c < '0' || c > '9')
return(0);
min = min * 10 + c - '0';
}
if (n != 0)
return(0);
return((maj << 8) | min);
}
#endif /* ASKDEV */
#if FASTLOAD
/*===========================================================================*
* fastload *
*===========================================================================*/
PRIVATE void fastload(boot_dev, address)
dev_t boot_dev;
char *address;
{
register i, blocks;
register long position;
blocks = lastused(boot_dev);
printf("Loading RAM disk. To load: %4DK Loaded: 0K %c",
((long)blocks * BLOCK_SIZE) / 1024, 0);
position = 0;
while (blocks) {
i = blocks;
if (i > (18*1024)/BLOCK_SIZE)
i = (18*1024)/BLOCK_SIZE;
blocks -= i;
i *= BLOCK_SIZE;
m1.m_type = DISK_READ;
m1.DEVICE = (boot_dev >> MINOR) & BYTE;
m1.POSITION = position;
m1.PROC_NR = HARDWARE;
m1.ADDRESS = address;
m1.COUNT = i;
(*dmap[(boot_dev >> MAJOR) & BYTE].dmap_rw)(
dmap[(boot_dev >> MAJOR) & BYTE].dmap_task,
&m1
);
if (m1.REP_STATUS < 0)
panic("Disk error loading BOOT disk", m1.REP_STATUS);
position += i;
address += i;
printf("\b\b\b\b\b\b%4DK %c", position / 1024L, 0);
}
}
/*===========================================================================*
* lastused *
*===========================================================================*/
PRIVATE int lastused(boot_dev)
dev_t boot_dev;
{
register i, w, b, last, this, zbase;
register struct super_block *sp = &super_block[0];
register struct buf *bp;
register short *wptr, *wlim;
zbase = SUPER_BLOCK + 1 + sp->s_imap_blocks;
this = sp->s_firstdatazone;
last = this - 1;
for (i = 0; i < sp->s_zmap_blocks; i++) {
bp = get_block(boot_dev, (block_nr) zbase + i, NORMAL);
wptr = (short *)&bp->b_data[0];
wlim = (short *)&bp->b_data[BLOCK_SIZE];
while (wptr != wlim) {
w = *wptr++;
for (b = 0; b < 8*sizeof(*wptr); b++) {
if (this == sp->s_nzones) {
put_block(bp, ZMAP_BLOCK);
return(last << sp->s_log_zone_size);
}
if ((w>>b) & 1)
last = this;
this++;
}
}
put_block(bp, ZMAP_BLOCK);
}
panic("lastused", NO_NUM);
}
#endif /* FASTLOAD */
/*===========================================================================*
* get_boot_parameters *
*===========================================================================*/
PUBLIC struct bparam_s boot_parameters = /* overwritten if new kernel */
{
DROOTDEV, DRAMIMAGEDEV, DRAMSIZE, DSCANCODE,
};
PRIVATE void get_boot_parameters()
{
/* Ask kernel for boot parameters. */
struct bparam_s temp_parameters;
m1.m_type = SYS_GBOOT;
m1.PROC1 = FS_PROC_NR;
m1.MEM_PTR = (char *) &temp_parameters;
if (sendrec(SYSTASK, &m1) == OK && m1.m_type == OK)
boot_parameters = temp_parameters;
}
#if (CHIP == INTEL)
/*===========================================================================*
* get_physbase *
*===========================================================================*/
PRIVATE phys_bytes get_physbase()
{
/* Ask kernel for base of fs data space. */
m1.m_type = SYS_UMAP;
m1.SRC_PROC_NR = FS_PROC_NR;
m1.SRC_SPACE = D;
m1.SRC_BUFFER = 0;
m1.COPY_BYTES = 1;
if (sendrec(SYSTASK, &m1) != OK || m1.SRC_BUFFER == 0)
panic("Can't get fs base", NO_NUM);
return m1.SRC_BUFFER;
}
#endif /* INTEL */