Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!mcvax!oce!sch From: sch@oce.nl (Jakob Schripsema) Newsgroups: comp.os.minix Subject: MINIX on Olivetti M24 (1 of 2) Message-ID: <195@oce-rd4.oce.nl> Date: Mon, 27-Apr-87 07:28:31 EDT Article-I.D.: oce-rd4.195 Posted: Mon Apr 27 07:28:31 1987 Date-Received: Wed, 29-Apr-87 05:16:11 EDT Reply-To: sch@oce-rd4.UUCP (Jakob Schripsema) Organization: Oce-Nederland bv, Venlo, the Netherlands Lines: 1423 echo x - f_make. sed 's/^X//' >f_make. <<'*-*-END-of-f_make.-*-*' XCFLAGS= -Di8088 -w -F -T. Xh=../h Xl=/usr/lib X Xobj = main.s open.s read.s write.s pipe.s device.s \ X path.s mount.s link.s super.s inode.s cache.s filedes.s \ X stadir.s protect.s time.s misc.s utility.s table.s putc.s X Xfs: makefile $l/head.s $(obj) $l/libc.a $l/end.s X# @echo "Start linking FS. /lib/cem will be removed to make space on RAM disk" X# @rm -f /lib/cem /tmp/* X# asld -o fs $l/head.s $(obj) $l/libc.a $l/end.s X# @echo "FS done. Please restore /lib/cem manually" X @echo "Start linking FS. X @asld -o fs -T. $l/head.s $(obj) $l/libc.a $l/end.s X @echo "FS done. X Xcache.s: const.h type.h $h/const.h $h/type.h Xcache.s: $h/error.h Xcache.s: buf.h Xcache.s: file.h Xcache.s: fproc.h Xcache.s: glo.h Xcache.s: inode.h Xcache.s: super.h X Xdevice.s: const.h type.h $h/const.h $h/type.h Xdevice.s: $h/com.h Xdevice.s: $h/error.h Xdevice.s: dev.h Xdevice.s: file.h Xdevice.s: fproc.h Xdevice.s: glo.h Xdevice.s: inode.h Xdevice.s: param.h X Xfiledes.s: const.h type.h $h/const.h $h/type.h Xfiledes.s: $h/error.h Xfiledes.s: file.h Xfiledes.s: fproc.h Xfiledes.s: glo.h Xfiledes.s: inode.h X Xinode.s: const.h type.h $h/const.h $h/type.h Xinode.s: $h/error.h Xinode.s: buf.h Xinode.s: file.h Xinode.s: fproc.h Xinode.s: glo.h Xinode.s: inode.h Xinode.s: super.h X Xlink.s: const.h type.h $h/const.h $h/type.h Xlink.s: $h/error.h Xlink.s: buf.h Xlink.s: file.h Xlink.s: fproc.h Xlink.s: glo.h Xlink.s: inode.h Xlink.s: param.h X Xmain.s: const.h type.h $h/const.h $h/type.h Xmain.s: $h/callnr.h Xmain.s: $h/com.h Xmain.s: $h/error.h Xmain.s: buf.h Xmain.s: file.h Xmain.s: fproc.h Xmain.s: glo.h Xmain.s: inode.h Xmain.s: param.h Xmain.s: super.h X Xmisc.s: const.h type.h $h/const.h $h/type.h Xmisc.s: $h/callnr.h Xmisc.s: $h/com.h Xmisc.s: $h/error.h Xmisc.s: buf.h Xmisc.s: file.h Xmisc.s: fproc.h Xmisc.s: glo.h Xmisc.s: inode.h Xmisc.s: param.h Xmisc.s: super.h X Xmount.s: const.h type.h $h/const.h $h/type.h Xmount.s: $h/error.h Xmount.s: buf.h Xmount.s: file.h Xmount.s: fproc.h Xmount.s: glo.h Xmount.s: inode.h Xmount.s: param.h Xmount.s: super.h X Xopen.s: const.h type.h $h/const.h $h/type.h Xopen.s: $h/callnr.h Xopen.s: $h/error.h Xopen.s: buf.h Xopen.s: file.h Xopen.s: fproc.h Xopen.s: glo.h Xopen.s: inode.h Xopen.s: param.h X Xpath.s: const.h type.h $h/const.h $h/type.h Xpath.s: $h/error.h Xpath.s: buf.h Xpath.s: file.h Xpath.s: fproc.h Xpath.s: glo.h Xpath.s: inode.h Xpath.s: super.h X Xpipe.s: const.h type.h $h/const.h $h/type.h Xpipe.s: $h/callnr.h Xpipe.s: $h/com.h Xpipe.s: $h/error.h Xpipe.s: $h/signal.h Xpipe.s: file.h Xpipe.s: fproc.h Xpipe.s: glo.h Xpipe.s: inode.h Xpipe.s: param.h X Xprotect.s: const.h type.h $h/const.h $h/type.h Xprotect.s: $h/error.h Xprotect.s: buf.h Xprotect.s: file.h Xprotect.s: fproc.h Xprotect.s: glo.h Xprotect.s: inode.h Xprotect.s: param.h Xprotect.s: super.h X Xputc.s: const.h type.h $h/const.h $h/type.h Xputc.s: $h/com.h X Xread.s: const.h type.h $h/const.h $h/type.h Xread.s: $h/com.h Xread.s: $h/error.h Xread.s: buf.h Xread.s: file.h Xread.s: fproc.h Xread.s: glo.h Xread.s: inode.h Xread.s: param.h Xread.s: super.h X Xstadir.s: const.h type.h $h/const.h $h/type.h Xstadir.s: $h/error.h Xstadir.s: $h/stat.h Xstadir.s: file.h Xstadir.s: fproc.h Xstadir.s: glo.h Xstadir.s: inode.h Xstadir.s: param.h X Xsuper.s: const.h type.h $h/const.h $h/type.h Xsuper.s: $h/error.h Xsuper.s: buf.h Xsuper.s: inode.h Xsuper.s: super.h X Xtable.s: const.h type.h $h/const.h $h/type.h Xtable.s: $h/com.h Xtable.s: $h/callnr.h Xtable.s: $h/error.h Xtable.s: $h/stat.h Xtable.s: buf.h Xtable.s: dev.h Xtable.s: file.h Xtable.s: fproc.h Xtable.s: glo.h Xtable.s: inode.h Xtable.s: super.h X Xtime.s: const.h type.h $h/const.h $h/type.h Xtime.s: $h/callnr.h Xtime.s: $h/com.h Xtime.s: $h/error.h Xtime.s: file.h Xtime.s: fproc.h Xtime.s: glo.h Xtime.s: inode.h Xtime.s: param.h X Xutility.s: const.h type.h $h/const.h $h/type.h Xutility.s: $h/com.h Xutility.s: $h/error.h Xutility.s: buf.h Xutility.s: file.h Xutility.s: fproc.h Xutility.s: glo.h Xutility.s: inode.h Xutility.s: param.h Xutility.s: super.h X Xwrite.s: const.h type.h $h/const.h $h/type.h Xwrite.s: $h/error.h Xwrite.s: buf.h Xwrite.s: file.h Xwrite.s: fproc.h Xwrite.s: glo.h Xwrite.s: inode.h Xwrite.s: super.h *-*-END-of-f_make.-*-* echo x - h_const.h sed 's/^X//' >h_const.h <<'*-*-END-of-h_const.h-*-*' X/* Copyright (C) 1987 by Prentice-Hall, Inc. Permission is hereby granted to X * private individuals and educational institutions to modify and X * redistribute the binary and source programs of this system to other X * private individuals and educational institutions for educational and X * research purposes. For corporate or commercial use, permission from X * Prentice-Hall is required. In general, such permission will be granted, X * subject to a few conditions. X */ X X#define EXTERN extern /* used in *.h files */ X#define PRIVATE static /* PRIVATE x limits the scope of x */ X#define PUBLIC /* PUBLIC is the opposite of PRIVATE */ X#define FORWARD /* some compilers require this to be 'static' */ X X#define TRUE 1 /* used for turning integers into Booleans */ X#define FALSE 0 /* used for turning integers into Booleans */ X X#define HZ 60 /* clock freq (software settable on IBM-PC) */ X#define BLOCK_SIZE 1024 /* # bytes in a disk block */ X#define SUPER_USER (uid) 0 /* uid of superuser */ X X#define MAJOR 8 /* major device = (dev>>MAJOR) & 0377 */ X#define MINOR 0 /* minor device = (dev>>MINOR) & 0377 */ X X#define NR_TASKS 8 /* number of tasks in the transfer vector */ X#define NR_PROCS 16 /* number of slots in proc table */ X#define NR_SEGS 3 /* # segments per process */ X#define T 0 /* proc[i].mem_map[T] is for text */ X#define D 1 /* proc[i].mem_map[D] is for data */ X#define S 2 /* proc[i].mem_map[S] is for stack */ X X#define MAX_P_LONG 2147483647 /* maximum positive long, i.e. 2**31 - 1 */ X X/* Memory is allocated in clicks. */ X#define CLICK_SIZE 0020 /* unit in which memory is allocated */ X#define CLICK_SHIFT 4 /* log2 of CLICK_SIZE */ X X/* Process numbers of some important processes */ X#define MM_PROC_NR 0 /* process number of memory manager */ X#define FS_PROC_NR 1 /* process number of file system */ X#define INIT_PROC_NR 2 /* init -- the process that goes multiuser */ X#define LOW_USER 2 /* first user not part of operating system */ X X/* Miscellaneous */ X#define BYTE 0377 /* mask for 8 bits */ X#define TO_USER 0 /* flag telling to copy from fs to user */ X#define FROM_USER 1 /* flag telling to copy from user to fs */ X#define READING 0 /* copy data to user */ X#define WRITING 1 /* copy data from user */ X#define ABS -999 /* this process means absolute memory */ X X#define WORD_SIZE 2 /* number of bytes per word */ X X#define NIL_PTR (char *) 0 /* generally useful expression */ X X#define NO_NUM 0x8000 /* used as numerical argument to panic() */ X#define MAX_PATH 128 /* max length of path names */ X#define SIG_PUSH_BYTES 8 /* how many bytes pushed by signal */ X#define MAX_ISTACK_BYTES 1024 /* maximum initial stack size for EXEC */ X X/* Device numbers of root (RAM) and boot (fd0) devices. */ X#define ROOT_DEV (dev_nr) 256 /* major-minor device number of root dev */ X/* bootdev fd0 : 512, hd2 : 770 */ X#define BOOT_DEV (dev_nr) 770 /* major-minor device number of boot diskette */ X X/* Flag bits for i_mode in the inode. */ X#define I_TYPE 0170000 /* this field gives inode type */ X#define I_REGULAR 0100000 /* regular file, not dir or special */ X#define I_BLOCK_SPECIAL 0060000 /* block special file */ X#define I_DIRECTORY 0040000 /* file is a directory */ X#define I_CHAR_SPECIAL 0020000 /* character special file */ X#define I_SET_UID_BIT 0004000 /* set effective uid on exec */ X#define I_SET_GID_BIT 0002000 /* set effective gid on exec */ X#define ALL_MODES 0006777 /* all bits for user, group and others */ X#define RWX_MODES 0000777 /* mode bits for RWX only */ X#define R_BIT 0000004 /* Rwx protection bit */ X#define W_BIT 0000002 /* rWx protection bit */ X#define X_BIT 0000001 /* rwX protection bit */ X#define I_NOT_ALLOC 0000000 /* this inode is free */ *-*-END-of-h_const.h-*-* echo x - k_const.h sed 's/^X//' >k_const.h <<'*-*-END-of-k_const.h-*-*' X/* General constants used by the kernel. */ X X#ifdef i8088 X/* p_reg contains: ax, bx, cx, dx, si, di, bp, es, ds, cs, ss in that order. */ X#define NR_REGS 11 /* number of general regs in each proc slot */ X#define INIT_PSW 0x0200 /* initial psw */ X#define INIT_SP (int*)0x0010 /* initial sp: 3 words pushed by kernel */ X X/* The following values are used in the assembly code. Do not change the X * values of 'ES_REG', 'DS_REG', 'CS_REG', or 'SS_REG' without making the X * corresponding changes in the assembly code. X */ X#define ES_REG 7 /* proc[i].p_reg[ESREG] is saved es */ X#define DS_REG 8 /* proc[i].p_reg[DSREG] is saved ds */ X#define CS_REG 9 /* proc[i].p_reg[CSREG] is saved cs */ X#define SS_REG 10 /* proc[i].p_reg[SSREG] is saved ss */ X X#define VECTOR_BYTES 284 /* bytes of interrupt vectors to save */ X#define MEM_BYTES 655360L /* memory size for /dev/mem */ X X/* Interrupt vectors */ X#define DIVIDE_VECTOR 0 /* divide interrupt vector */ X#define CLOCK_VECTOR 8 /* clock interrupt vector */ X#define KEYBOARD_VECTOR 9 /* keyboard interrupt vector */ X#define XT_WINI_VECTOR 13 /* xt winchester interrupt vector */ X#define FLOPPY_VECTOR 14 /* floppy disk interrupt vector */ X#define PRINTER_VECTOR 15 /* line printer interrupt vector */ X#define SYS_VECTOR 32 /* system calls are made with int SYSVEC */ X#define AT_WINI_VECTOR 118 /* at winchester interrupt vector */ X X/* The 8259A interrupt controller has to be re-enabled after each interrupt. */ X#define INT_CTL 0x20 /* I/O port for interrupt controller */ X#define INT_CTLMASK 0x21 /* setting bits in this port disables ints */ X#define INT2_CTL 0xA0 /* I/O port for second interrupt controller */ X#define INT2_MASK 0xA1 /* setting bits in this port disables ints */ X#define ENABLE 0x20 /* code used to re-enable after an interrupt */ X X/* Hardware IDs */ X#define UNKNOWN 0 /* OS could not detect hrdware type */ X#define IBMXT 1 /* IBM XT */ X#define IBMAT 2 /* IBM AT */ X#define M24 3 /* Olivetti M24, AT&T 6300 */ X#endif X X#define TASK_STACK_BYTES 256 /* how many bytes for each task stack */ X#define K_STACK_BYTES 256 /* how many bytes for the kernel stack */ X X#define RET_REG 0 /* system call return codes go in this reg */ X#define IDLE -999 /* 'cur_proc' = IDLE means nobody is running */ X X/* The following items pertain to the 3 scheduling queues. */ X#define NQ 3 /* # of scheduling queues */ X#define TASK_Q 0 /* ready tasks are scheduled via queue 0 */ X#define SERVER_Q 1 /* ready servers are scheduled via queue 1 */ X#define USER_Q 2 /* ready users are scheduled via queue 2 */ X X#define printf printk /* the kernel really uses printk, not printf */ *-*-END-of-k_const.h-*-* echo x - k_floppy.c sed 's/^X//' >k_floppy.c <<'*-*-END-of-k_floppy.c-*-*' X/* This file contains a driver for a Floppy Disk Controller (FDC) using the X * NEC PD765 chip. The driver supports two operations: read a block and X * write a block. It accepts two messages, one for reading and one for X * writing, both using message format m2 and with the same parameters: X * X * m_type DEVICE PROC_NR COUNT POSITION ADRRESS X * ---------------------------------------------------------------- X * | DISK_READ | device | proc nr | bytes | offset | buf ptr | X * |------------+---------+---------+---------+---------+---------| X * | DISK_WRITE | device | proc nr | bytes | offset | buf ptr | X * ---------------------------------------------------------------- X * X * The file contains one entry point: X * X * floppy_task: main entry when system is brought up X * X * Changes: X * 27 october 1986 by Jakob Schripsema: fdc_results fixed for 8 MHz X * 2 februari 1987 by Jakob Schripsema: added timeout() routine X * & reset counter X */ X X#include "../h/const.h" X#include "../h/type.h" X#include "../h/callnr.h" X#include "../h/com.h" X#include "../h/error.h" X#include "const.h" X#include "type.h" X#include "glo.h" X#include "proc.h" X X/* I/O Ports used by floppy disk task. */ X#define DOR 0x3F2 /* motor drive control bits */ X#define FDC_STATUS 0x3F4 /* floppy disk controller status register */ X#define FDC_DATA 0x3F5 /* floppy disk controller data register */ X#define FDC_RATE 0x3F7 /* transfer rate register */ X#define DMA_ADDR 0x004 /* port for low 16 bits of DMA address */ X#define DMA_TOP 0x081 /* port for top 4 bits of 20-bit DMA addr */ X#define DMA_COUNT 0x005 /* port for DMA count (count = bytes - 1) */ X#define DMA_M2 0x00C /* DMA status port */ X#define DMA_M1 0x00B /* DMA status port */ X#define DMA_INIT 0x00A /* DMA init port */ X X/* Status registers returned as result of operation. */ X#define ST0 0x00 /* status register 0 */ X#define ST1 0x01 /* status register 1 */ X#define ST2 0x02 /* status register 2 */ X#define ST3 0x00 /* status register 3 (return by DRIVE_SENSE) */ X#define ST_CYL 0x03 /* slot where controller reports cylinder */ X#define ST_HEAD 0x04 /* slot where controller reports head */ X#define ST_SEC 0x05 /* slot where controller reports sector */ X#define ST_PCN 0x01 /* slot where controller reports present cyl */ X X/* Fields within the I/O ports. */ X#define MASTER 0x80 /* used to see who is master */ X#define DIRECTION 0x40 /* is FDC trying to read or write? */ X#define CTL_BUSY 0x10 /* used to see when controller is busy */ X#define CTL_ACCEPTING 0x80 /* bit pattern FDC gives when idle */ X#define MOTOR_MASK 0xF0 /* these bits control the motors in DOR */ X#define ENABLE_INT 0x0C /* used for setting DOR port */ X#define ST0_BITS 0xF8 /* check top 5 bits of seek status */ X#define ST3_FAULT 0x80 /* if this bit is set, drive is sick */ X#define ST3_WR_PROTECT 0x40 /* set when diskette is write protected */ X#define ST3_READY 0x20 /* set when drive is ready */ X#define TRANS_ST0 0x00 /* top 5 bits of ST0 for READ/WRITE */ X#define SEEK_ST0 0x20 /* top 5 bits of ST0 for SEEK */ X#define BAD_SECTOR 0x05 /* if these bits are set in ST1, recalibrate */ X#define BAD_CYL 0x1F /* if any of these bits are set, recalibrate */ X#define WRITE_PROTECT 0x02 /* bit is set if diskette is write protected */ X#define CHANGE 0xC0 /* value returned by FDC after reset */ X X/* Floppy disk controller command bytes. */ X#define FDC_SEEK 0x0F /* command the drive to seek */ X#define FDC_READ 0xE6 /* command the drive to read */ X#define FDC_WRITE 0xC5 /* command the drive to write */ X#define FDC_SENSE 0x08 /* command the controller to tell its status */ X#define FDC_RECALIBRATE 0x07 /* command the drive to go to cyl 0 */ X#define FDC_SPECIFY 0x03 /* command the drive to accept params */ X X/* DMA channel commands. */ X#define DMA_READ 0x46 /* DMA read opcode */ X#define DMA_WRITE 0x4A /* DMA write opcode */ X X/* Parameters for the disk drive. */ X#define SECTOR_SIZE 512 /* physical sector size in bytes */ X#define HC_SIZE 2400 /* # sectors on a high-capacity (1.2M) disk */ X#define NR_HEADS 0x02 /* two heads (i.e., two tracks/cylinder) */ X#define DTL 0xFF /* determines data length (sector size) */ X#define SPEC1 0xDF /* first parameter to SPECIFY */ X#define SPEC2 0x02 /* second parameter to SPECIFY */ X X#define MOTOR_OFF 3*HZ /* how long to wait before stopping motor */ X#define TIMEOUT 2*HZ /* how long to wait before aborting transfer */ X X/* Error codes */ X#define ERR_SEEK -1 /* bad seek */ X#define ERR_TRANSFER -2 /* bad transfer */ X#define ERR_STATUS -3 /* something wrong when getting status */ X#define ERR_RECALIBRATE -4 /* recalibrate didn't work properly */ X#define ERR_WR_PROTECT -5 /* diskette is write protected */ X#define ERR_DRIVE -6 /* something wrong with a drive */ X#define ERR_TIMEOUT -7 /* timeout, drive not ready */ X X/* Miscellaneous. */ X#define MOTOR_RUNNING 0xFF /* message type for clock interrupt */ X#define MAX_ERRORS 20 /* how often to try rd/wt before quitting */ X#define MAX_RESETS 2 /* max number of resets for 1 job */ X#define MAX_RESULTS 8 /* max number of bytes controller returns */ X#define NR_DRIVES 2 /* maximum number of drives */ X#define DIVISOR 128 /* used for sector size encoding */ X#define MAX_FDC_RETRY 100 /* max # times to try to output to FDC */ X#define NT 4 /* number of diskette/drive combinations */ X X/* Variables. */ XPRIVATE struct floppy { /* main drive struct, one entry per drive */ X int fl_opcode; /* DISK_READ or DISK_WRITE */ X int fl_curcyl; /* current cylinder */ X int fl_procnr; /* which proc wanted this operation? */ X int fl_drive; /* drive number addressed */ X int fl_cylinder; /* cylinder number addressed */ X int fl_sector; /* sector addressed */ X int fl_head; /* head number addressed */ X int fl_count; /* byte count */ X vir_bytes fl_address; /* user virtual address */ X char fl_results[MAX_RESULTS]; /* the controller can give lots of output */ X char fl_calibration; /* CALIBRATED or UNCALIBRATED */ X char fl_density; /* 0 = 360K/360K; 1 = 360K/1.2M; 2= 1.2M/1.2M */ X} floppy[NR_DRIVES]; X X#define UNCALIBRATED 0 /* drive needs to be calibrated at next use */ X#define CALIBRATED 1 /* no calibration needed */ X XPRIVATE int motor_status; /* current motor status is in 4 high bits */ XPRIVATE int motor_goal; /* desired motor status is in 4 high bits */ XPRIVATE int prev_motor; /* which motor was started last */ XPRIVATE int need_reset; /* set to 1 when controller must be reset */ XPRIVATE int nresets; /* # of resets during 1 'job' */ XPRIVATE int initialized; /* set to 1 after first successful transfer */ XPRIVATE int d; /* diskette/drive combination */ XPRIVATE int active_timeout; /* used to detect timeout in transfer */ X XPRIVATE message mess; /* message buffer for in and out */ X XPRIVATE char len[] = {-1,0,1,-1,2,-1,-1,3,-1,-1,-1,-1,-1,-1,-1,4}; XPRIVATE char interleave[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; X X/* Four combinations of diskette/drive are supported: X * # Drive diskette Sectors Tracks Rotation Data-rate Comment X * 0 360K 360K 9 40 300 RPM 250 kbps Standard PC DSDD X * 1 720K 360K 9 40 300 RPM 250 kbps Quad density PC X * 2 1.2M 360K 9 40 360 RPM 300 kbps PC disk in AT drive X * 3 1.2M 1.2M 15 80 360 RPM 500 kbps AT disk in AT drive X */ XPRIVATE int gap[NT] = {0x2A, 0x2A, 0x23, 0x1B}; /* gap size */ XPRIVATE int rate[NT] = {0x02, 0x02, 0x01, 0x00}; /* 250,300,500 kbps*/ XPRIVATE int nr_sectors[NT] = {9, 9, 9, 15}; /* sectors/track */ XPRIVATE int nr_blocks[NT] = {720, 720, 720, 2400}; /* sectors/diskette*/ XPRIVATE int steps_per_cyl[NT] = {1, 2, 2, 1}; /* 2 = dbl step */ XPRIVATE int mtr_setup[NT] = {HZ/4,HZ/4,3*HZ/4,3*HZ/4};/* in ticks */ X X/*===========================================================================* X * floppy_task * X *===========================================================================*/ XPUBLIC floppy_task() X{ X/* Main program of the floppy disk driver task. */ X X int r, caller, proc_nr; X extern int hw_id; X X if (hw_id == M24) mtr_setup[0] = 3*HZ/4; X X /* Here is the main loop of the disk task. It waits for a message, carries X * it out, and sends a reply. X */ X while (TRUE) { X /* First wait for a request to read or write a disk block. */ X receive(ANY, &mess); /* get a request to do some work */ X if (mess.m_source < 0) X panic("disk task got message from ", mess.m_source); X caller = mess.m_source; X proc_nr = mess.PROC_NR; X X /* Now carry out the work. */ X switch(mess.m_type) { X case DISK_READ: r = do_rdwt(&mess); break; X case DISK_WRITE: r = do_rdwt(&mess); break; X default: r = EINVAL; break; X } X X /* Finally, prepare and send the reply message. */ X mess.m_type = TASK_REPLY; X mess.REP_PROC_NR = proc_nr; X mess.REP_STATUS = r; /* # of bytes transferred or error code */ X send(caller, &mess); /* send reply to caller */ X } X} X X X/*===========================================================================* X * do_rdwt * X *===========================================================================*/ XPRIVATE int do_rdwt(m_ptr) Xmessage *m_ptr; /* pointer to read or write message */ X{ X/* Carry out a read or write request from the disk. */ X register struct floppy *fp; X int r, drive, errors, stop_motor(); X long block; X X /* Decode the message parameters. */ X drive = m_ptr->DEVICE; X if (drive < 0 || drive >= NR_DRIVES) return(EIO); X fp = &floppy[drive]; /* 'fp' points to entry for this drive */ X fp->fl_drive = drive; /* save drive number explicitly */ X fp->fl_opcode = m_ptr->m_type; /* DISK_READ or DISK_WRITE */ X if (m_ptr->POSITION % BLOCK_SIZE != 0) return(EINVAL); X block = m_ptr->POSITION/SECTOR_SIZE; X if (block >= HC_SIZE) return(EOF); /* sector is beyond end of 1.2M disk */ X d = fp->fl_density; /* diskette/drive combination */ X fp->fl_cylinder = (int) (block / (NR_HEADS * nr_sectors[d])); X fp->fl_sector = (int) interleave[block % nr_sectors[d]]; X fp->fl_head = (int) (block % (NR_HEADS*nr_sectors[d]) )/nr_sectors[d]; X fp->fl_count = m_ptr->COUNT; X fp->fl_address = (vir_bytes) m_ptr->ADDRESS; X fp->fl_procnr = m_ptr->PROC_NR; X if (fp->fl_count != BLOCK_SIZE) return(EINVAL); X X errors = 0; X nresets = 0; X X /* This loop allows a failed operation to be repeated. */ X while (errors <= MAX_ERRORS) { X X /* If a lot of errors occur when 'initialized' is 0, it probably X * means that we are trying at the wrong density. Try another one. X * Increment 'errors' here since loop is aborted on error. X */ X errors++; /* increment count once per loop cycle */ X if (errors % (MAX_ERRORS/NT) == 0) { X d = (d + 1) % NT; /* try next density */ X fp->fl_density = d; X need_reset = 1; X } X if (block >= nr_blocks[d]) continue; X X /* First check to see if a reset is needed. */ X if (need_reset) reset(); X if (nresets > MAX_RESETS) return(ERR_DRIVE); X X /* Now set up the DMA chip. */ X dma_setup(fp); X X /* See if motor is running; if not, turn it on and wait */ X start_motor(fp); X X /* If we are going to a new cylinder, perform a seek. */ X r = seek(fp); X if (r != OK) continue; /* if error, try again */ X X /* Perform the transfer. */ X r = transfer(fp); X if (r == OK) break; /* if successful, exit loop */ X if (r == ERR_WR_PROTECT || r == ERR_TIMEOUT) break; /* retries won't help */ X X } X X /* Start watch_dog timer to turn motor off in a few seconds */ X motor_goal = ENABLE_INT; /* when timer goes off, kill all motors */ X clock_mess(MOTOR_OFF, stop_motor); X if (r == OK && fp->fl_cylinder > 0) initialized = 1; /* seek works */ X return(r == OK ? BLOCK_SIZE : EIO); X} X X/*===========================================================================* X * dma_setup * X *===========================================================================*/ XPRIVATE dma_setup(fp) Xstruct floppy *fp; /* pointer to the drive struct */ X{ X/* The IBM PC can perform DMA operations by using the DMA chip. To use it, X * the DMA (Direct Memory Access) chip is loaded with the 20-bit memory address X * to be read from or written to, the byte count minus 1, and a read or write X * opcode. This routine sets up the DMA chip. Note that the chip is not X * capable of doing a DMA across a 64K boundary (e.g., you can't read a X * 512-byte block starting at physical address 65520). X */ X X int mode, low_addr, high_addr, top_addr, low_ct, high_ct, top_end; X vir_bytes vir, ct; X phys_bytes user_phys; X extern phys_bytes umap(); X X mode = (fp->fl_opcode == DISK_READ ? DMA_READ : DMA_WRITE); X vir = (vir_bytes) fp->fl_address; X ct = (vir_bytes) fp->fl_count; X user_phys = umap(proc_addr(fp->fl_procnr), D, vir, ct); X low_addr = (int) (user_phys >> 0) & BYTE; X high_addr = (int) (user_phys >> 8) & BYTE; X top_addr = (int) (user_phys >> 16) & BYTE; X low_ct = (int) ( (ct - 1) >> 0) & BYTE; X high_ct = (int) ( (ct - 1) >> 8) & BYTE; X X /* Check to see if the transfer will require the DMA address counter to X * go from one 64K segment to another. If so, do not even start it, since X * the hardware does not carry from bit 15 to bit 16 of the DMA address. X * Also check for bad buffer address. These errors mean FS contains a bug. X */ X if (user_phys == 0) panic("FS gave floppy disk driver bad addr", (int) vir); X top_end = (int) (((user_phys + ct - 1) >> 16) & BYTE); X if (top_end != top_addr) panic("Trying to DMA across 64K boundary", top_addr); X X /* Now set up the DMA registers. */ X lock(); X port_out(DMA_M2, mode); /* set the DMA mode */ X port_out(DMA_M1, mode); /* set it again */ X port_out(DMA_ADDR, low_addr); /* output low-order 8 bits */ X port_out(DMA_ADDR, high_addr);/* output next 8 bits */ X port_out(DMA_TOP, top_addr); /* output highest 4 bits */ X port_out(DMA_COUNT, low_ct); /* output low 8 bits of count - 1 */ X port_out(DMA_COUNT, high_ct); /* output high 8 bits of count - 1 */ X unlock(); X port_out(DMA_INIT, 2); /* initialize DMA */ X} X X X/*===========================================================================* X * start_motor * X *===========================================================================*/ XPRIVATE start_motor(fp) Xstruct floppy *fp; /* pointer to the drive struct */ X{ X/* Control of the floppy disk motors is a big pain. If a motor is off, you X * have to turn it on first, which takes 1/2 second. You can't leave it on X * all the time, since that would wear out the diskette. However, if you turn X * the motor off after each operation, the system performance will be awful. X * The compromise used here is to leave it on for a few seconds after each X * operation. If a new operation is started in that interval, it need not be X * turned on again. If no new operation is started, a timer goes off and the X * motor is turned off. I/O port DOR has bits to control each of 4 drives. X * Interrupts must be disabled temporarily to prevent clock interrupt from X * turning off motors while we are testing the bits. X */ X X int motor_bit, running, send_mess(); X X lock(); /* no interrupts while checking out motor */ X motor_bit = 1 << (fp->fl_drive + 4); /* bit mask for this drive */ X motor_goal = motor_bit | ENABLE_INT | fp->fl_drive; X if (motor_status & prev_motor) motor_goal |= prev_motor; X running = motor_status & motor_bit; /* nonzero if this motor is running */ X port_out(DOR, motor_goal); X motor_status = motor_goal; X prev_motor = motor_bit; /* record motor started for next time */ X unlock(); X X /* If the motor was already running, we don't have to wait for it. */ X if (running) return; /* motor was already running */ X clock_mess(mtr_setup[d], send_mess); /* motor was not running */ X receive(CLOCK, &mess); /* wait for clock interrupt */ X} X X X/*===========================================================================* X * stop_motor * X *===========================================================================*/ XPRIVATE stop_motor() X{ X/* This routine is called by the clock interrupt after several seconds have X * elapsed with no floppy disk activity. It checks to see if any drives are X * supposed to be turned off, and if so, turns them off. X */ X X if ( (motor_goal & MOTOR_MASK) != (motor_status & MOTOR_MASK) ) { X port_out(DOR, motor_goal); X motor_status = motor_goal; X } X} X X X/*===========================================================================* X * seek * X *===========================================================================*/ XPRIVATE int seek(fp) Xstruct floppy *fp; /* pointer to the drive struct */ X{ X/* Issue a SEEK command on the indicated drive unless the arm is already X * positioned on the correct cylinder. X */ X X int r; X extern int timeout(); X X /* Are we already on the correct cylinder? */ X if (fp->fl_calibration == UNCALIBRATED) X if (recalibrate(fp) != OK) return(ERR_SEEK); X if (fp->fl_curcyl == fp->fl_cylinder) return(OK); X X /* No. Wrong cylinder. Issue a SEEK and wait for interrupt. */ X fdc_out(FDC_SEEK); /* start issuing the SEEK command */ X fdc_out( (fp->fl_head << 2) | fp->fl_drive); X fdc_out(fp->fl_cylinder * steps_per_cyl[d]); X if (need_reset) return(ERR_SEEK); /* if controller is sick, abort seek */ X receive(HARDWARE, &mess); X X /* Interrupt has been received. Check drive status. */ X fdc_out(FDC_SENSE); /* probe FDC to make it return status */ X r = fdc_results(fp); /* get controller status bytes */ X if ( (fp->fl_results[ST0] & ST0_BITS) != SEEK_ST0) r = ERR_SEEK; X if (fp->fl_results[ST1] != fp->fl_cylinder * steps_per_cyl[d]) r = ERR_SEEK; X if (r != OK) X if (recalibrate(fp) != OK) return(ERR_SEEK); X return(r); X} X X X/*===========================================================================* X * transfer * X *===========================================================================*/ XPRIVATE int transfer(fp) Xregister struct floppy *fp; /* pointer to the drive struct */ X{ X/* The drive is now on the proper cylinder. Read or write 1 block. */ X X int r, s, op; X extern int olivetti; X extern int timeout(); X X /* Never attempt a transfer if the drive is uncalibrated or motor is off. */ X if (fp->fl_calibration == UNCALIBRATED) return(ERR_TRANSFER); X if ( ( (motor_status>>(fp->fl_drive+4)) & 1) == 0) return(ERR_TRANSFER); X X /* The PC-AT requires the date rate to be set to 250 or 500 kbps */ X if (hw_id == IBMAT) port_out(FDC_RATE, rate[d]); X X /* The command is issued by outputing 9 bytes to the controller chip. */ X op = (fp->fl_opcode == DISK_READ ? FDC_READ : FDC_WRITE); X fdc_out(op); /* issue the read or write command */ X fdc_out( (fp->fl_head << 2) | fp->fl_drive); X fdc_out(fp->fl_cylinder); /* tell controller which cylinder */ X fdc_out(fp->fl_head); /* tell controller which head */ X fdc_out(fp->fl_sector); /* tell controller which sector */ X fdc_out( (int) len[SECTOR_SIZE/DIVISOR]); /* sector size */ X fdc_out(nr_sectors[d]); /* tell controller how big a track is */ X fdc_out(gap[d]); /* tell controller how big sector gap is */ X fdc_out(DTL); /* tell controller about data length */ X X /* Block, waiting for disk interrupt. */ X if (need_reset) return(ERR_TRANSFER); /* if controller is sick, abort op */ X clock_mess(TIMEOUT,timeout); /* start timer */ X active_timeout = TRUE; /* and set flag to remember this */ X X receive(HARDWARE, &mess); X X /* Check for timeout */ X if (active_timeout == FALSE) return(ERR_TIMEOUT); X active_timeout = FALSE; /* all done, forget about timeout */ X X /* Get controller status and check for errors. */ X r = fdc_results(fp); X if (r != OK) return(r); X if ( (fp->fl_results[ST1] & BAD_SECTOR) || (fp->fl_results[ST2] & BAD_CYL) ) X fp->fl_calibration = UNCALIBRATED; X if (fp->fl_results[ST1] & WRITE_PROTECT) { X printf("Diskette in drive %d is write protected.\n", fp->fl_drive); X return(ERR_WR_PROTECT); X } X if ((fp->fl_results[ST0] & ST0_BITS) != TRANS_ST0) return(ERR_TRANSFER); X if (fp->fl_results[ST1] | fp->fl_results[ST2]) return(ERR_TRANSFER); X X /* Compare actual numbers of sectors transferred with expected number. */ X s = (fp->fl_results[ST_CYL] - fp->fl_cylinder) * NR_HEADS * nr_sectors[d]; X s += (fp->fl_results[ST_HEAD] - fp->fl_head) * nr_sectors[d]; X s += (fp->fl_results[ST_SEC] - fp->fl_sector); X if (s * SECTOR_SIZE != fp->fl_count) return(ERR_TRANSFER); X return(OK); X} X X/*===========================================================================* X * timeout * X *===========================================================================*/ XPRIVATE int timeout() X{ X/* The NEC 765 fdc has its ready line tied to Vcc. So it's impossible X * to check a drives ready state. If a drive isn't ready and a read or X * write is started in transfer(), the fdc waits until the drive gets ready. X * This blocks both the floppy task and FS until the drive gets ready. X * Solution : X * Before transfer() does a receive() it starts a timeout. X * If the timer runs out this routine is called. When no interrupt has X * occured in the mean time (active_timeout still TRUE) the disk probably X * isn't ready. To get the floppy task out of its deadlock the fdc is reset. X * After a reset the fdc detects 'drive-ready' (ready line still tied to X * Vcc !!) and generates a 'drive-status-changed' interrupt (see 765 spec.) X * The interrupt routine sends a message to the floppy task which readies X * the floppy task. X * As usual the problem is with the IBM PC hardware. X */ X X if (active_timeout == FALSE) return; /* no work to do */ X X /* Start fdc reset */ X lock(); X port_out(DOR, 0); /* strobe reset bit low */ X port_out(DOR, ENABLE_INT); /* strobe it high again */ X unlock(); /* interrupts allowed again */ X X need_reset = TRUE; X active_timeout = FALSE; X} X X/*===========================================================================* X * fdc_results * X *===========================================================================*/ XPRIVATE int fdc_results(fp) Xregister struct floppy *fp; /* pointer to the drive struct */ X{ X/* Extract results from the controller after an operation. */ X X int i, j, status, ready; X X /* Loop, extracting bytes from FDC until it says it has no more. */ X for (i = 0; i < MAX_RESULTS; i++) { X ready = FALSE; X for (j = 0; j < MAX_FDC_RETRY; j++) { X port_in(FDC_STATUS, &status); X if (status & MASTER) { X ready = TRUE; X break; X } X } X if (ready == FALSE) return(ERR_STATUS); /* time out */ X X if ((status & CTL_BUSY) == 0) return(OK); X if ((status & DIRECTION) == 0) return(ERR_STATUS); X port_in(FDC_DATA, &status); X fp->fl_results[i] = status & BYTE; X } X X /* FDC is giving back too many results. */ X need_reset = TRUE; /* controller chip must be reset */ X return(ERR_STATUS); X} X X X/*===========================================================================* X * fdc_out * X *===========================================================================*/ XPRIVATE fdc_out(val) Xint val; /* write this byte to floppy disk controller */ X{ X/* Output a byte to the controller. This is not entirely trivial, since you X * can only write to it when it is listening, and it decides when to listen. X * If the controller refuses to listen, the FDC chip is given a hard reset. X */ X X int retries, r; X X if (need_reset) return; /* if controller is not listening, return */ X retries = MAX_FDC_RETRY; X X /* It may take several tries to get the FDC to accept a command. */ X while (retries-- > 0) { X port_in(FDC_STATUS, &r); X r &= (MASTER | DIRECTION); /* just look at bits 2 and 3 */ X if (r != CTL_ACCEPTING) continue; /* FDC is not listening */ X port_out(FDC_DATA, val); X return; X } X X /* Controller is not listening. Hit it over the head with a hammer. */ X need_reset = TRUE; X} X X X/*===========================================================================* X * recalibrate * X *===========================================================================*/ XPRIVATE int recalibrate(fp) Xregister struct floppy *fp; /* pointer tot he drive struct */ X{ X/* The floppy disk controller has no way of determining its absolute arm X * position (cylinder). Instead, it steps the arm a cylinder at a time and X * keeps track of where it thinks it is (in software). However, after a X * SEEK, the hardware reads information from the diskette telling where the X * arm actually is. If the arm is in the wrong place, a recalibration is done, X * which forces the arm to cylinder 0. This way the controller can get back X * into sync with reality. X */ X X int r; X /* Issue the RECALIBRATE command and wait for the interrupt. */ X start_motor(fp); /* can't recalibrate with motor off */ X fdc_out(FDC_RECALIBRATE); /* tell drive to recalibrate itself */ X fdc_out(fp->fl_drive); /* specify drive */ X if (need_reset) return(ERR_SEEK); /* don't wait if controller is sick */ X receive(HARDWARE, &mess); /* wait for interrupt message */ X X /* Determine if the recalibration succeeded. */ X fdc_out(FDC_SENSE); /* issue SENSE command to see where we are */ X r = fdc_results(fp); /* get results of the SENSE command */ X fp->fl_curcyl = -1; /* force a SEEK next time */ X if (r != OK || /* controller would not respond */ X (fp->fl_results[ST0]&ST0_BITS) != SEEK_ST0 || fp->fl_results[ST_PCN] !=0){ X /* Recalibration failed. FDC must be reset. */ X need_reset = TRUE; X fp->fl_calibration = UNCALIBRATED; X return(ERR_RECALIBRATE); X } else { X /* Recalibration succeeded. */ X fp->fl_calibration = CALIBRATED; X return(OK); X } X} X X/*===========================================================================* X * reset * X *===========================================================================*/ XPRIVATE reset() X{ X/* Issue a reset to the controller. This is done after any catastrophe, X * like the controller refusing to respond. X */ X X int i, r, status; X register struct floppy *fp; X X /* Disable interrupts and strobe reset bit low. */ X need_reset = FALSE; X lock(); X motor_status = 0; X motor_goal = 0; X port_out(DOR, 0); /* strobe reset bit low */ X port_out(DOR, ENABLE_INT); /* strobe it high again */ X unlock(); /* interrupts allowed again */ X receive(HARDWARE, &mess); /* collect the RESET interrupt */ X X /* Interrupt from the reset has been received. Continue resetting. */ X fp = &floppy[0]; /* use floppy[0] for scratch */ X fp->fl_results[0] = 0; /* this byte will be checked shortly */ X fdc_out(FDC_SENSE); /* did it work? */ X r = fdc_results(fp); /* get results */ X status = fp->fl_results[0] & BYTE; X X /* Tell FDC drive parameters. */ X fdc_out(FDC_SPECIFY); /* specify some timing parameters */ X fdc_out(SPEC1); /* step-rate and head-unload-time */ X fdc_out(SPEC2); /* head-load-time and non-dma */ X X for (i = 0; i < NR_DRIVES; i++) floppy[i].fl_calibration = UNCALIBRATED; X X nresets++; /* count this reset */ X} X X X/*===========================================================================* X * clock_mess * X *===========================================================================*/ XPRIVATE clock_mess(ticks, func) Xint ticks; /* how many clock ticks to wait */ Xint (*func)(); /* function to call upon time out */ X{ X/* Send the clock task a message. */ X X mess.m_type = SET_ALARM; X mess.CLOCK_PROC_NR = FLOPPY; X mess.DELTA_TICKS = ticks; X mess.FUNC_TO_CALL = func; X sendrec(CLOCK, &mess); X} X X X/*===========================================================================* X * send_mess * X *===========================================================================*/ XPRIVATE send_mess() X{ X/* This routine is called when the clock task has timed out on motor startup.*/ X X mess.m_type = MOTOR_RUNNING; X send(FLOPPY, &mess); X} *-*-END-of-k_floppy.c-*-* echo x - k_glo.h sed 's/^X//' >k_glo.h <<'*-*-END-of-k_glo.h-*-*' X/* Global variables used in the kernel. */ X X/* Clocks and timers */ XEXTERN real_time realtime; /* real time clock */ XEXTERN int lost_ticks; /* incremented when clock int can't send mess*/ X X/* Processes, signals, and messages. */ XEXTERN int cur_proc; /* current process */ XEXTERN int prev_proc; /* previous process */ XEXTERN int sig_procs; /* number of procs with p_pending != 0 */ XEXTERN message int_mess; /* interrupt routines build message here */ X X/* CPU type. */ XEXTERN int olivetti; /* TRUE for Olivetti-style keyboard */ XEXTERN int hw_id; /* identification of hardware */ X X/* The kernel and task stacks. */ XEXTERN struct t_stack { X int stk[TASK_STACK_BYTES/sizeof(int)]; X} t_stack[NR_TASKS - 1]; /* task stacks; task = -1 never really runs */ X XEXTERN char k_stack[K_STACK_BYTES]; /* The kernel stack. */ *-*-END-of-k_glo.h-*-* echo x - k_main.c sed 's/^X//' >k_main.c <<'*-*-END-of-k_main.c-*-*' X/* This file contains the main program of MINIX. The routine main() X * initializes the system and starts the ball rolling by setting up the proc X * table, interrupt vectors, and scheduling each task to run to initialize X * itself. X * X * The entries into this file are: X * main: MINIX main program X * unexpected_int: called when an interrupt to an unused vector < 16 occurs X * trap: called when an unexpected trap to a vector >= 16 occurs X * panic: abort MINIX due to a fatal error X */ X X#include "../h/const.h" X#include "../h/type.h" X#include "../h/callnr.h" X#include "../h/com.h" X#include "../h/error.h" X#include "const.h" X#include "type.h" X#include "glo.h" X#include "proc.h" X X#define SAFETY 8 /* margin of safety for stack overflow (ints)*/ X#define VERY_BIG 39328 /* must be bigger than kernel size (clicks) */ X#define BASE 1536 /* address where MINIX starts in memory */ X#define SIZES 8 /* sizes array has 8 entries */ X#define CPU_TY1 0xFFFF /* BIOS segment that tells CPU type */ X#define CPU_TY2 0x000E /* BIOS offset that tells CPU type */ X#define PC_AT 0xFC /* IBM code for PC-AT (in BIOS at 0xFFFFE) */ X X/*===========================================================================* X * main * X *===========================================================================*/ XPUBLIC main() X{ X/* Start the ball rolling. */ X X register struct proc *rp; X register int t; X vir_clicks size; X phys_clicks base_click, mm_base, previous_base; X phys_bytes phys_b; X extern unsigned sizes[8]; /* table filled in by build */ X extern int color, vec_table[], get_chrome(), (*task[])(); X extern int s_call(), disk_int(), tty_int(), clock_int(), disk_int(); X extern int wini_int(), lpr_int(), surprise(), trp(), divide(); X extern phys_bytes umap(); X X /* Set up proc table entry for user processes. Be very careful about X * sp, since the 3 words prior to it will be clobbered when the kernel pushes X * pc, cs, and psw onto the USER's stack when starting the user the first X * time. This means that with initial sp = 0x10, user programs must leave X * the words at 0x000A, 0x000C, and 0x000E free. X */ X X lock(); /* we can't handle interrupts yet */ X base_click = BASE >> CLICK_SHIFT; X size = sizes[0] + sizes[1]; /* kernel text + data size in clicks */ X mm_base = base_click + size; /* place where MM starts (in clicks) */ X X for (rp = &proc[0]; rp <= &proc[NR_TASKS+LOW_USER]; rp++) { X for (t=0; t< NR_REGS; t++) rp->p_reg[t] = 0100*t; /* debugging */ X t = rp - proc - NR_TASKS; /* task number */ X rp->p_sp = (rp < &proc[NR_TASKS] ? t_stack[NR_TASKS+t+1].stk : INIT_SP); X rp->p_splimit = rp->p_sp; X if (rp->p_splimit != INIT_SP) X rp->p_splimit -= (TASK_STACK_BYTES - SAFETY)/sizeof(int); X rp->p_pcpsw.pc = task[t + NR_TASKS]; X if (rp->p_pcpsw.pc != 0 || t >= 0) ready(rp); X rp->p_pcpsw.psw = INIT_PSW; X rp->p_flags = 0; X X /* Set up memory map for tasks and MM, FS, INIT. */ X if (t < 0) { X /* I/O tasks. */ X rp->p_map[T].mem_len = VERY_BIG; X rp->p_map[T].mem_phys = base_click; X rp->p_map[D].mem_len = VERY_BIG; X rp->p_map[D].mem_phys = base_click + sizes[0]; X rp->p_map[S].mem_len = VERY_BIG; X rp->p_map[S].mem_phys = base_click + sizes[0] + sizes[1]; X rp->p_map[S].mem_vir = sizes[0] + sizes[1]; X } else { X /* MM, FS, and INIT. */ X previous_base = proc[NR_TASKS + t - 1].p_map[S].mem_phys; X rp->p_map[T].mem_len = sizes[2*t + 2]; X rp->p_map[T].mem_phys = (t == 0 ? mm_base : previous_base); X rp->p_map[D].mem_len = sizes[2*t + 3]; X rp->p_map[D].mem_phys = rp->p_map[T].mem_phys + sizes[2*t + 2]; X rp->p_map[S].mem_vir = sizes[2*t + 3]; X rp->p_map[S].mem_phys = rp->p_map[D].mem_phys + sizes[2*t + 3]; X } X X#ifdef i8088 X rp->p_reg[CS_REG] = rp->p_map[T].mem_phys; X rp->p_reg[DS_REG] = rp->p_map[D].mem_phys; X rp->p_reg[SS_REG] = rp->p_map[D].mem_phys; X rp->p_reg[ES_REG] = rp->p_map[D].mem_phys; X#endif X } X X proc[NR_TASKS+(HARDWARE)].p_sp = (int *) k_stack; X proc[NR_TASKS+(HARDWARE)].p_sp += K_STACK_BYTES/2; X proc[NR_TASKS+(HARDWARE)].p_splimit = (int *) k_stack; X proc[NR_TASKS+(HARDWARE)].p_splimit += SAFETY/2; X X for (rp = proc_addr(LOW_USER+1); rp < proc_addr(NR_PROCS); rp++) X rp->p_flags = P_SLOT_FREE; X X /* Determine if display is color or monochrome and CPU type (from BIOS). */ X color = get_chrome(); /* 0 = mono, 1 = color */ X hw_id = UNKNOWN; X t = get_byte(CPU_TY1, CPU_TY2); /* is this PC, XT, AT ... ? */ X if (t == PC_AT) hw_id = IBMAT; X if (hw_id == UNKNOWN && is_m24() == OK) hw_id = M24; X X /* Save the old interrupt vectors. */ X phys_b = umap(proc_addr(HARDWARE), D, (vir_bytes) vec_table, VECTOR_BYTES); X phys_copy(0L, phys_b, (long) VECTOR_BYTES); /* save all the vectors */ X X /* Set up the new interrupt vectors. */ X for (t = 0; t < 16; t++) set_vec(t, surprise, base_click); X for (t = 16; t < 256; t++) set_vec(t, trp, base_click); X set_vec(DIVIDE_VECTOR, divide, base_click); X set_vec(SYS_VECTOR, s_call, base_click); X set_vec(CLOCK_VECTOR, clock_int, base_click); X set_vec(KEYBOARD_VECTOR, tty_int, base_click); X set_vec(FLOPPY_VECTOR, disk_int, base_click); X set_vec(PRINTER_VECTOR, lpr_int, base_click); X if (hw_id == IBMAT) X set_vec(AT_WINI_VECTOR, wini_int, base_click); X else X set_vec(XT_WINI_VECTOR, wini_int, base_click); X X /* Put a ptr to proc table in a known place so it can be found in /dev/mem */ X set_vec( (BASE - 4)/4, proc, (phys_clicks) 0); X X bill_ptr = proc_addr(HARDWARE); /* it has to point somewhere */ X pick_proc(); X X /* Now go to the assembly code to start running the current process. */ X port_out(INT_CTLMASK, 0); /* do not mask out any interrupts in 8259A */ X port_out(INT2_MASK, 0); /* same for second interrupt controller */ X restart(); X} X X X/*===========================================================================* X * unexpected_int * X *===========================================================================*/ XPUBLIC unexpected_int() X{ X/* A trap or interrupt has occurred that was not expected. */ X X printf("Unexpected trap: vector < 16\n"); X printf("pc = 0x%x text+data+bss = 0x%x\n",proc_ptr->p_pcpsw.pc, X proc_ptr->p_map[D].mem_len<<4); X} X X X/*===========================================================================* X * trap * X *===========================================================================*/ XPUBLIC trap() X{ X/* A trap (vector >= 16) has occurred. It was not expected. */ X X printf("\nUnexpected trap: vector >= 16 "); X printf("This may be due to accidentally including\n"); X printf("a non-MINIX library routine that is trying to make a system call.\n"); X printf("pc = 0x%x text+data+bss = 0x%x\n",proc_ptr->p_pcpsw.pc, X proc_ptr->p_map[D].mem_len<<4); X} X X X/*===========================================================================* X * div_trap * X *===========================================================================*/ XPUBLIC div_trap() X{ X/* The divide intruction traps to vector 0 upon overflow. */ X X printf("Trap to vector 0: divide overflow. "); X printf("pc = 0x%x text+data+bss = 0x%x\n",proc_ptr->p_pcpsw.pc, X proc_ptr->p_map[D].mem_len<<4); X} X X X/*===========================================================================* X * panic * X *===========================================================================*/ XPUBLIC panic(s,n) Xchar *s; Xint n; X{ X/* The system has run aground of a fatal error. Terminate execution. X * If the panic originated in MM or FS, the string will be empty and the X * file system already syncked. If the panic originates in the kernel, we are X * kind of stuck. X */ X X if (*s != 0) { X printf("\nKernel panic: %s",s); X if (n != NO_NUM) printf(" %d", n); X printf("\n"); X } X printf("\nType space to reboot\n"); X wreboot(); X X} X X#ifdef i8088 X/*===========================================================================* X * set_vec * X *===========================================================================*/ XPRIVATE set_vec(vec_nr, addr, base_click) Xint vec_nr; /* which vector */ Xint (*addr)(); /* where to start */ Xphys_clicks base_click; /* click where kernel sits in memory */ X{ X/* Set up an interrupt vector. */ X X unsigned vec[2]; X unsigned u; X phys_bytes phys_b; X extern unsigned sizes[8]; X X /* Build the vector in the array 'vec'. */ X vec[0] = (unsigned) addr; X vec[1] = (unsigned) base_click; X u = (unsigned) vec; X X /* Copy the vector into place. */ X phys_b = ( (phys_bytes) base_click + (phys_bytes) sizes[0]) << CLICK_SHIFT; X phys_b += u; X phys_copy(phys_b, (phys_bytes) 4*vec_nr, (phys_bytes) 4); X} X#endif X X/*===========================================================================* X * is_m24 * X *===========================================================================*/ XPRIVATE is_m24() X{ X/* Reads the BIOS to to check is the hardware is a Olivetti M24 X * This routine works for BIOS versions 1.1, 1.21 and 1.36 X */ X X char buffer[9]; X phys_bytes buffaddr; X X /* read copyright string at FC00:50 */ X buffaddr = umap(proc_addr(HARDWARE), D, (vir_bytes) buffer, 8); X phys_copy(0xFC050L, buffaddr, 8L); X X /* test string */ X buffer[8] = '\0'; X if(strcmp(buffer,"OLIVETTI") == 0) X return(TRUE); X return(FALSE); X} *-*-END-of-k_main.c-*-* echo x - k_make. sed 's/^X//' >k_make. <<'*-*-END-of-k_make.-*-*' X# The kernel directory contains files xt_wini.c and at_wini.c. Before running X# make you must copy one of these to wini.c, depending on whether you have a X# PC or an AT. You must do this even if you do not have a hard disk.. XCFLAGS= -Di8088 -w -F -T. Xh=../h Xl=/usr/lib X Xobj = mpx88.s main.s proc.s system.s tty.s clock.s memory.s floppy.s wini.s \ X printer.s table.s klib88.s dmp.s X Xkernel: makefile $(obj) $l/libc.a X# @echo "Start linking Kernel. /lib/* will be removed to make space on RAM disk" X# @rm -f /lib/cem /lib/cpp /tmp/* X# @asld -o kernel $(obj) $l/libc.a $l/end.s X# @echo "Kernel done. Please restore /lib/cem and /lib/cpp manually" X @echo "Start linking Kernel." X @asld -o kernel -T. $(obj) $l/libc.a $l/end.s X @echo "Kernel done." X Xclock.s: const.h type.h $h/const.h $h/type.h Xclock.s: $h/callnr.h Xclock.s: $h/com.h Xclock.s: $h/error.h Xclock.s: $h/signal.h Xclock.s: glo.h Xclock.s: proc.h X Xfloppy.s: const.h type.h $h/const.h $h/type.h Xfloppy.s: $h/callnr.h Xfloppy.s: $h/com.h Xfloppy.s: $h/error.h Xfloppy.s: glo.h Xfloppy.s: proc.h X X Xdmp.s: const.h type.h $h/const.h $h/type.h Xdmp.s: $h/callnr.h Xdmp.s: $h/com.h Xdmp.s: $h/error.h Xdmp.s: glo.h Xdmp.s: proc.h X Xmain.s: const.h type.h $h/const.h $h/type.h Xmain.s: $h/callnr.h Xmain.s: $h/com.h Xmain.s: $h/error.h Xmain.s: glo.h Xmain.s: proc.h X Xmemory.s: const.h type.h $h/const.h $h/type.h Xmemory.s: $h/callnr.h Xmemory.s: $h/com.h Xmemory.s: $h/error.h Xmemory.s: proc.h X Xprinter.s: const.h type.h $h/const.h $h/type.h Xprinter.s: $h/callnr.h Xprinter.s: $h/com.h Xprinter.s: $h/error.h X Xproc.s: const.h type.h $h/const.h $h/type.h Xproc.s: $h/callnr.h Xproc.s: $h/com.h Xproc.s: $h/error.h Xproc.s: glo.h Xproc.s: proc.h X Xsystem.s: const.h type.h $h/const.h $h/type.h Xsystem.s: $h/callnr.h Xsystem.s: $h/com.h Xsystem.s: $h/error.h Xsystem.s: $h/signal.h Xsystem.s: glo.h Xsystem.s: proc.h X Xtable.s: const.h type.h $h/const.h $h/type.h Xtable.s: glo.h Xtable.s: proc.h X Xtty.s: const.h type.h $h/const.h $h/type.h Xtty.s: $h/callnr.h Xtty.s: $h/com.h Xtty.s: $h/error.h Xtty.s: $h/sgtty.h Xtty.s: $h/signal.h Xtty.s: glo.h Xtty.s: proc.h X Xwini.s: const.h type.h $h/const.h $h/type.h Xwini.s: $h/callnr.h Xwini.s: $h/com.h Xwini.s: $h/error.h Xwini.s: proc.h *-*-END-of-k_makmmmb d; /*