diff --git a/Makefile b/Makefile index f31a1df4a..0c2ea7150 100755 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ usage: # 'make install' target. # # etcfiles has to be done first. -world: includes depend libraries cmds install postinstall +world: includes depend cmds install postinstall includes: cd include && $(MAKE) install gcc diff --git a/boot/boot.c b/boot/boot.c index eae2ae75c..ddd04fca5 100755 --- a/boot/boot.c +++ b/boot/boot.c @@ -18,6 +18,7 @@ char version[]= "2.20"; #include #include #include +#include #include #include #include @@ -28,6 +29,7 @@ char version[]= "2.20"; #if BIOS #include #include +#include #endif #if UNIX #include @@ -46,6 +48,10 @@ char version[]= "2.20"; #define arraylimit(a) ((a) + arraysize(a)) #define between(a, c, z) ((unsigned) ((c) - (a)) <= ((z) - (a))) +u16_t vid_port; /* Video i/o port. */ +u32_t vid_mem_base; /* Video memory base address. */ +u32_t vid_mem_size; /* Video memory size. */ + int fsok= -1; /* File system state. Initially unknown. */ static int block_size; @@ -590,6 +596,19 @@ void initialize(void) bootdev.name[5] += bootdev.secondary; } + /* Find out about the video hardware. */ + raw_copy(mon2abs(&vid_port), VDU_CRT_BASE_ADDR, sizeof(vid_port)); + if(vid_port == C_6845) { + vid_mem_base = COLOR_BASE; + vid_mem_size = COLOR_SIZE; + } else { + vid_mem_base = MONO_BASE; + vid_mem_size = MONO_SIZE; + } + + if(get_video() >= 3) + vid_mem_size = EGA_SIZE; + #else /* DOS */ /* Take the monitor out of the memory map if we have memory to spare, * note that only half our PSP is needed at the new place, the first @@ -1959,3 +1978,4 @@ void main(int argc, char **argv) /* * $PchId: boot.c,v 1.14 2002/02/27 19:46:14 philip Exp $ */ + diff --git a/boot/bootimage.c b/boot/bootimage.c index fcedfd720..66354c173 100755 --- a/boot/bootimage.c +++ b/boot/bootimage.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include #include @@ -27,6 +29,10 @@ static int block_size = 0; +extern u16_t vid_port; /* Video i/o port. */ +extern u32_t vid_mem_base; /* Video memory base address. */ +extern u32_t vid_mem_size; /* Video memory size. */ + #define click_shift clck_shft /* 7 char clash with click_size. */ /* Some kernels have extra features: */ @@ -376,6 +382,42 @@ int get_segment(u32_t *vsec, long *size, u32_t *addr, u32_t limit) return 1; } +static void restore_screen(void) +{ + struct boot_tty_info boot_tty_info; + u32_t info_location; +#define LINES 25 +#define CHARS 80 + static u16_t consolescreen[LINES][CHARS]; + + /* Try and find out what the main console was displaying + * by looking into video memory. + */ + + info_location = vid_mem_base+vid_mem_size-sizeof(boot_tty_info); + raw_copy(mon2abs(&boot_tty_info), info_location, + sizeof(boot_tty_info)); + + if(boot_tty_info.magic == TTYMAGIC) { + if(boot_tty_info.flags & (BTIF_CONSORIGIN|BTIF_CONSCURSOR) == + (BTIF_CONSORIGIN|BTIF_CONSCURSOR)) { + int line; + raw_copy(mon2abs(consolescreen), + vid_mem_base + boot_tty_info.consorigin, + sizeof(consolescreen)); + clear_screen(); + for(line = 0; line < LINES; line++) { + int ch; + for(ch = 0; ch < CHARS; ch++) { + u16_t newch = consolescreen[line][ch] & BYTE; + if(newch < ' ') newch = ' '; + putch(newch); + } + } + } + } +} + void exec_image(char *image) /* Get a Minix image into core, patch it up and execute. */ { @@ -607,8 +649,13 @@ void exec_image(char *image) /* Read leftover character, if any. */ scan_keyboard(); + + /* Restore screen contents. */ + restore_screen(); } + + ino_t latest_version(char *version, struct stat *stp) /* Recursively read the current directory, selecting the newest image on * the way up. (One can't use r_stat while reading a directory.) diff --git a/boot/rawfs.c b/boot/rawfs.c index 06ec2f50f..27b25c984 100755 --- a/boot/rawfs.c +++ b/boot/rawfs.c @@ -61,7 +61,7 @@ static char dirbuf[_MAX_BLOCK_SIZE]; /* Scratch/Directory block. */ static block_t a_indir, a_dindir; /* Addresses of the indirects. */ static off_t dirpos; /* Reading pos in a dir. */ -#define fsbuf(b) (* (struct buf *) (b)) +#define fsbuf(b) (* (union fsdata_u *) (b)) #define zone_shift (super.s_log_zone_size) /* zone to block ratio */ @@ -110,6 +110,7 @@ void r_stat(Ino_t inum, struct stat *stp) block_t block; block_t ino_block; ino_t ino_offset; + union fsdata_u *blockbuf; /* Calculate start of i-list */ block = START_BLOCK + super.s_imap_blocks + super.s_zmap_blocks; @@ -120,13 +121,14 @@ void r_stat(Ino_t inum, struct stat *stp) block += ino_block; /* Fetch the block */ - readblock(block, scratch, block_size); + blockbuf = (union fsdata_u *) scratch; + readblock(block, blockbuf, block_size); if (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3) { d2_inode *dip; int i; - dip= &fsbuf(scratch).b_v2_ino[ino_offset]; + dip= &blockbuf->b__v2_ino[ino_offset]; curfil.i_mode= dip->d2_mode; curfil.i_nlinks= dip->d2_nlinks; @@ -142,7 +144,7 @@ void r_stat(Ino_t inum, struct stat *stp) d1_inode *dip; int i; - dip= &fsbuf(scratch).b_v1_ino[ino_offset]; + dip= &blockbuf->b__v1_ino[ino_offset]; curfil.i_mode= dip->d1_mode; curfil.i_nlinks= dip->d1_nlinks; @@ -263,8 +265,8 @@ off_t r_vir2abs(off_t virblk) i = zone / (zone_t) nr_indirects; ind_zone = (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3) - ? fsbuf(dindir).b_v2_ind[i] - : fsbuf(dindir).b_v1_ind[i]; + ? fsbuf(dindir).b__v2_ind[i] + : fsbuf(dindir).b__v1_ind[i]; zone %= (zone_t) nr_indirects; } if (ind_zone == 0) return 0; @@ -276,8 +278,8 @@ off_t r_vir2abs(off_t virblk) a_indir= z; } zone = (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3) - ? fsbuf(indir).b_v2_ind[(int) zone] - : fsbuf(indir).b_v1_ind[(int) zone]; + ? fsbuf(indir).b__v2_ind[(int) zone] + : fsbuf(indir).b__v1_ind[(int) zone]; /* Calculate absolute datablock number */ z = ((block_t) zone << zone_shift) + zone_index; diff --git a/commands/Makefile b/commands/Makefile index 3f51f484c..930c9b18c 100755 --- a/commands/Makefile +++ b/commands/Makefile @@ -4,7 +4,7 @@ MAKE = exec make -$(MAKEFLAGS) BZIP2=bzip2-1.0.3 FLEX=flex-2.5.4 -SMALLPROGRAMS=`arch` aal advent ash autil awk byacc cawf cron de dhcpd dis88 elle elvis ftp101 ftpd200 ibm indent m4 make mdb mined patch pax profile ps reboot rlogind scripts sh simple syslogd talk talkd telnet telnetd urlget yap zoneinfo +SMALLPROGRAMS=`arch` aal advent ash autil awk byacc cawf cron de dhcpd dis88 elle elvis ftp101 ftpd200 ibm indent m4 make mined patch pax profile ps reboot rlogind scripts sh simple syslogd talk talkd telnet telnetd urlget yap usage: @echo "Usage: make all # Compile all commands" >&2 diff --git a/commands/ash/Makefile b/commands/ash/Makefile index 108bba28a..3acb338fe 100755 --- a/commands/ash/Makefile +++ b/commands/ash/Makefile @@ -55,16 +55,16 @@ sh: $(OBJS) install: /usr/bin/ash /usr/bin/sh /bin/sh /bin/bigsh /usr/bin/ash: sh - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/sh: /usr/bin/ash - install -l $? $@ + install -l $< $@ /bin/sh: /usr/bin/ash - install -lcs $? $@ + install -lcs $< $@ /bin/bigsh: /usr/bin/ash - install -S 6600k -lcs $? $@ + install -S 6600k -lcs $< $@ clean: rm -f $(CLEANFILES) sh core @@ -75,7 +75,7 @@ token.def: mktokens sh mktokens arith.c: arith.y - $(YACC) -d $? + $(YACC) -d $< mv y.tab.c $@ mv y.tab.h arith_y.h diff --git a/commands/ibm/Makefile b/commands/ibm/Makefile index 95337f1a6..26f9b10a9 100755 --- a/commands/ibm/Makefile +++ b/commands/ibm/Makefile @@ -22,8 +22,7 @@ ALL = \ postmort \ recwave \ repartition \ - screendump \ - sdump \ + screendump all: $(ALL) @@ -109,7 +108,6 @@ install: \ /usr/bin/recwave \ /usr/bin/repartition \ /usr/bin/screendump \ - /usr/bin/sdump \ /bin/loadkeys \ /usr/bin/atnormalize: atnormalize diff --git a/commands/profile/sprofalyze.pl b/commands/profile/sprofalyze.pl index 3c2d7c08b..36caff904 100755 --- a/commands/profile/sprofalyze.pl +++ b/commands/profile/sprofalyze.pl @@ -30,11 +30,11 @@ servers/inet/inet servers/is/is servers/pm/pm servers/rs/rs +servers/vm/vm servers/rs/service drivers/at_wini/at_wini drivers/bios_wini/bios_wini -drivers/cmos/cmos drivers/dp8390/dp8390 drivers/dpeth/dpeth drivers/floppy/floppy diff --git a/commands/ps/ps.c b/commands/ps/ps.c index f6f5fe31d..fa82bdd33 100644 --- a/commands/ps/ps.c +++ b/commands/ps/ps.c @@ -84,6 +84,7 @@ #include "../../servers/pm/mproc.h" #include "../../servers/vfs/fproc.h" #include "../../servers/vfs/const.h" +#include "../../servers/mfs/const.h" /*----- ps's local stuff below this line ------*/ @@ -109,7 +110,9 @@ size_t n_ttyinfo; /* Number of tty info slots */ /* Number of tasks and processes and addresses of the main process tables. */ int nr_tasks, nr_procs; +#if 0 vir_bytes proc_addr, mproc_addr, fproc_addr; +#endif extern int errno; /* Process tables of the kernel, MM, and FS. */ @@ -315,10 +318,14 @@ char *argv[]; if ((memfd = open(MEM_PATH, O_RDONLY)) == -1) err(MEM_PATH); if (gettynames() == -1) err("Can't get tty names"); +#if 0 getsysinfo(PM_PROC_NR, SI_PROC_ADDR, &mproc_addr); getsysinfo(FS_PROC_NR, SI_PROC_ADDR, &fproc_addr); +#endif getsysinfo(PM_PROC_NR, SI_KINFO, &kinfo); +#if 0 proc_addr = kinfo.proc_addr; +#endif nr_tasks = kinfo.nr_tasks; nr_procs = kinfo.nr_procs; @@ -329,6 +336,7 @@ char *argv[]; if (ps_proc == NULL || ps_mproc == NULL || ps_fproc == NULL) err("Out of memory"); +#if 0 /* Get kernel process table */ if (addrread(kmemfd, (phys_clicks) 0, proc_addr, (char *) ps_proc, @@ -347,6 +355,17 @@ char *argv[]; nr_procs * sizeof(ps_fproc[0])) != nr_procs * sizeof(ps_fproc[0])) err("Can't get fs proc table from /dev/mem"); +#else + if(getsysinfo(PM_PROC_NR, SI_KPROC_TAB, ps_proc) < 0) { + fprintf(stderr, "getsysinfo() for SI_KPROC_TAB failed.\n"); + exit(1); + } + + if(getsysinfo(PM_PROC_NR, SI_PROC_TAB, ps_mproc) < 0) { + fprintf(stderr, "getsysinfo() for SI_PROC_TAB failed.\n"); + exit(1); + } +#endif /* We need to know where INIT hangs out. */ for (i = FS_PROC_NR; i < nr_procs; i++) { @@ -479,8 +498,13 @@ int endpoints; bufp->ps_flags = ps_proc[p_ki].p_rts_flags; if (p_nr >= low_user) { +#if 0 bufp->ps_dev = ps_fproc[p_nr].fp_tty; bufp->ps_ftask = ps_fproc[p_nr].fp_task; +#else + bufp->ps_dev = 0; + bufp->ps_ftask = 0; +#endif } else { bufp->ps_dev = 0; bufp->ps_ftask = 0; @@ -511,9 +535,11 @@ int endpoints; bufp->ps_state = T_STATE; /* stopped (traced) */ else if (ps_proc[p_ki].p_rts_flags == 0) bufp->ps_state = R_STATE; /* in run-queue */ +#if 0 else if (ps_mproc[p_nr].mp_flags & (WAITING | PAUSED | SIGSUSPENDED) || ps_fproc[p_nr].fp_suspended == SUSPENDED) bufp->ps_state = S_STATE; /* sleeping */ +#endif else bufp->ps_state = W_STATE; /* a short wait */ } else { /* tasks are simple */ diff --git a/commands/simple/Makefile b/commands/simple/Makefile index 31b0ac2de..8aa7fc4a6 100755 --- a/commands/simple/Makefile +++ b/commands/simple/Makefile @@ -16,7 +16,7 @@ CC = exec cc # all: $(ALL) default rule, make all binaries # # cat: cat.c 'cat' is made from 'cat.c' -# $(CCLD) -o $@ $? compile 'cat.c' ($?) to 'cat' ($@) +# $(CCLD) -o $@ $< compile 'cat.c' ($<) to 'cat' ($@) # install -S 4kw $@ stack size is 8k (8086) or 16k (others) # # install: \ rule to install all binaries @@ -24,11 +24,11 @@ CC = exec cc # /bin/cat \ important binaries are also in /bin # # /usr/bin/cat: cat -# install -cs -o bin $? $@ copy 'cat' to '/usr/bin/cat' (-c), +# install -cs -o bin $< $@ copy 'cat' to '/usr/bin/cat' (-c), # strip symbol table (-s) # # /bin/cat: /usr/bin/cat -# install -lcs $? $@ install '/bin/cat' by linking (if possible) +# install -lcs $< $@ install '/bin/cat' by linking (if possible) # or copying (otherwise) # # Some of the binaries are installed under more than one name. The extra @@ -108,7 +108,6 @@ ALL = \ isoread \ join \ kill \ - last \ leave \ life \ loadramdisk \ @@ -224,175 +223,175 @@ arp: arp.c $(CCLD) -o $@ arp.c at: at.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ backup: backup.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ badblocks: badblocks.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ banner: banner.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ basename: basename.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ cal: cal.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ calendar: calendar.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ cat: cat.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ cdiff: cdiff.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 28kw $@ cdprobe: cdprobe.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 28kw $@ cgrep: cgrep.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 5kw $@ chmem: chmem.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ chmod: chmod.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 16kw $@ chown: chown.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 16kw $@ chroot: chroot.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ ci: ci.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ cksum: cksum.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 8kw $@ cleantmp: cleantmp.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 8kw $@ cmp: cmp.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ co: co.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ comm: comm.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ compress: compress.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 450k $@ cp: cp.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 32kw $@ crc: crc.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 8kw $@ cut: cut.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ dd: dd.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 20kw $@ decomp16: decomp16.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ dev2name: dev2name.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ devsize: devsize.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ df: df.c - $(CCLD) -I$(SYS) -o $@ $? + $(CCLD) -I$(SYS) -o $@ $< @install -S 4kw $@ dhrystone: dhrystone.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ diff: diff.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 512kw $@ dirname: dirname.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ du: du.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 256kw $@ dumpcore: dumpcore.c - $(CCLD) -D_SYSTEM=1 -o $@ $? -lsysutil -lsys + $(CCLD) -D_SYSTEM=1 -o $@ $< -lsys @install -S 32k $@ ed: ed.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 32kw $@ eject: eject.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ env: env.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 50k $@ expand: expand.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ factor: factor.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ fgrep: fgrep.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 10kw $@ file: file.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 25kw $@ find: find.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 25kw $@ finger: finger.c @@ -404,19 +403,19 @@ fix: fix.c @install -S 32kw $@ fold: fold.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ fortune: fortune.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ fsck: fsck.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 8192k $@ fsck1: fsck1.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 32kw $@ getty: getty.c /usr/include/minix/config.h @@ -424,15 +423,15 @@ getty: getty.c /usr/include/minix/config.h @install -S 4kw $@ gomoku: gomoku.c - $(CCLD) -o $@ $? -lcurses + $(CCLD) -o $@ $< -lcurses @install -S 8kw $@ grep: grep.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 32kw $@ head: head.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ host: host.c @@ -444,7 +443,7 @@ hostaddr: hostaddr.c @install -S 8kw $@ id: id.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ ifconfig: ifconfig.c @@ -452,7 +451,7 @@ ifconfig: ifconfig.c @install -S 4kw $@ ifdef: ifdef.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ in.fingerd: in.fingerd.c @@ -464,182 +463,182 @@ in.rshd: in.rshd.c @install -S 8kw $@ installx: install.c # Note: avoided confict with 'install' rule. - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< intr: intr.c $(CCLD) -o $@ intr.c @install -S 4kw $@ irdpd: irdpd.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ isoread: isoread.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ join: join.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ kill: kill.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ last: last.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 5kw $@ leave: leave.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ life: life.c - $(CCLD) -o $@ $? -lcurses + $(CCLD) -o $@ $< -lcurses @install -S 15kw $@ loadramdisk: loadramdisk.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< install -S 4kw $@ login: login.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< install -S 4kw $@ look: look.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ lp: lp.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ lpd: lpd.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ ls: ls.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 20kw $@ mail: mail.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ man: man.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 10kw $@ mesg: mesg.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ mkdir: mkdir.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ mkfifo: mkfifo.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ mkfs: mkfs.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 25kw $@ mknod: mknod.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ mkproto: mkproto.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 20kw $@ mkswap: mkswap.c - $(CCLD) -I$(SYS) -o $@ $? + $(CCLD) -I$(SYS) -o $@ $< @install -S 4kw $@ modem: modem.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ mount: mount.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 12kw $@ mt: mt.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ newroot: newroot.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 32kw $@ nm: nm.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 32kw $@ nice: nice.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 8kw $@ nonamed: nonamed.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 8kw $@ od: od.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ passwd: passwd.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ paste: paste.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ ping: ping.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ pr: pr.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 16kw $@ pr_routes: pr_routes.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ progressbar: progressbar.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ prep: prep.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ printf: printf.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ printenv: printenv.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ printroot: printroot.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ proto: proto.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 15kw $@ pwd: pwd.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ pwdauth: pwdauth.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ ramdisk: ramdisk.c @@ -667,27 +666,27 @@ rev: rev.c @install -S 8kw $@ readall: readall.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ readfs: readfs.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 25kw $@ remsync: remsync.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 256k $@ rget: rget.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 8kw $@ rlogin: rlogin.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 8kw $@ rmdir: rmdir.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 15kw $@ rsh: rsh.c @@ -695,79 +694,79 @@ rsh: rsh.c @install -S 8kw $@ sed: sed.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 8kw $@ shar: shar.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ size: size.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ sleep: sleep.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ slip: slip.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 20k $@ sort: sort.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 30kw $@ split: split.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ stat: stat.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ strings: strings.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 8kw $@ strip: strip.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 8kw $@ stty: stty.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ su: su.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ sum: sum.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ swapfs: swapfs.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ sync: sync.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ synctree: synctree.c - $(CCLD) -o $@ -wo $? + $(CCLD) -o $@ -wo $< install -S 256kw $@ sysenv: sysenv.c - $(CCLD) -o $@ -wo $? + $(CCLD) -o $@ -wo $< @install -S 4kw $@ tail: tail.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 16kw $@ tar: tar.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 256kw $@ tcpd: tcpd.c @@ -783,62 +782,62 @@ tcpstat: tcpstat.c @install -S 8kw $@ tee: tee.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ term: term.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ termcap: termcap.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ tget: tget.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ time: time.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ touch: touch.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ top: top.c - $(CCLD) -o $@ $? -lcurses + $(CCLD) -o $@ $< -lcurses tr: tr.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ tsort: tsort.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ treecmp: treecmp.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ truncate: truncate.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ ttt: ttt.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ tty: tty.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ udpstat: udpstat.c - $(CCLD) -o $@ -I$(SERVERS) $? + $(CCLD) -o $@ -I$(SERVERS) $< @install -S 32k $@ umount: umount.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ uname: uname.c /usr/include/minix/config.h @@ -846,57 +845,57 @@ uname: uname.c /usr/include/minix/config.h @install -S 4kw $@ unexpand: unexpand.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ uniq: uniq.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ update: update.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 2kw $@ uud: uud.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ uue: uue.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ vol: vol.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 80k $@ # note: '-S' is upper limit to 'vol -m' wc: wc.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ which: which.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ who: who.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ whoami: whoami.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ write: write.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< writeisofs: writeisofs.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< xargs: xargs.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 16kw $@ yes: yes.c - $(CCLD) -o $@ $? + $(CCLD) -o $@ $< @install -S 4kw $@ install: \ @@ -989,8 +988,6 @@ install: \ /usr/bin/isoinfo \ /usr/bin/join \ /usr/bin/kill \ - /usr/bin/last \ - /usr/bin/uptime \ /usr/bin/leave \ /usr/bin/life \ /usr/bin/loadramdisk \ @@ -1116,611 +1113,611 @@ install: \ # /usr/bin/add_route: add_route - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/del_route: /usr/bin/add_route - install -l $? $@ + install -l $< $@ /usr/bin/arp: arp - install -cs -o root -m 4755 $? $@ + install -cs -o root -m 4755 $< $@ /usr/bin/at: at - install -cs -o root -m 4755 $? $@ + install -cs -o root -m 4755 $< $@ /usr/bin/backup: backup - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/restore: /usr/bin/backup - install -l $? $@ + install -l $< $@ /usr/bin/badblocks: badblocks - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/banner: banner - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/basename: basename - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/cal: cal - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/calendar: calendar - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/cat: cat - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/cdiff: cdiff - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/cdprobe: cdprobe - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/cgrep: cgrep - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/chmem: chmem - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/chmod: chmod - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/chown: chown - install -cs -o bin $? $@ + install -cs -o bin $< $@ /bin/chroot: chroot - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/chgrp: /usr/bin/chown - install -l $? $@ + install -l $< $@ /usr/bin/ci: ci - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/cksum: cksum - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/cleantmp: cleantmp - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/cmp: cmp - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/co: co - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/comm: comm - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/compress: compress - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/uncompress /usr/bin/zcat: /usr/bin/compress - install -l $? $@ + install -l $< $@ /bin/cp: cp - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/cp: cp - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/clone /usr/bin/cpdir \ /usr/bin/ln /usr/bin/mv /usr/bin/rm: /usr/bin/cp - install -l $? $@ + install -l $< $@ /bin/ln /bin/mv /bin/rm: /bin/cp - install -l $? $@ + install -l $< $@ /usr/bin/crc: crc - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/cut: cut - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/dd: dd - install -cs -o bin $? $@ + install -cs -o bin $< $@ /bin/dev2name: dev2name - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/devsize: devsize - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/decomp16: decomp16 - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/df: df - install -cs -o root -m 4755 $? $@ + install -cs -o root -m 4755 $< $@ /usr/bin/dhrystone: dhrystone - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/diff: diff - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/dirname: dirname - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/du: du - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/dumpcore: dumpcore - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/ed: ed - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/eject: eject - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/env: env - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/expand: expand - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/factor: factor - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/fgrep: fgrep - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/file: file - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/find: find - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/finger: finger - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/fix: fix - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/fold: fold - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/fortune: fortune - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/fsck: fsck - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/fsck1: fsck1 - install -cs -o bin $? $@ + install -cs -o bin $< $@ /bin/getty: getty - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/getty: getty - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/gomoku: gomoku - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/grep: grep - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/egrep: /usr/bin/grep - install -l $? $@ + install -l $< $@ /usr/bin/head: head - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/host: host - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/hostaddr: hostaddr - install -cs -o root -m 4755 $? $@ + install -cs -o root -m 4755 $< $@ /usr/bin/id: id - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/ifconfig: ifconfig - install -cs -o root -m 4755 $? $@ + install -cs -o root -m 4755 $< $@ /usr/bin/ifdef: ifdef - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/in.fingerd: in.fingerd - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/in.rshd: in.rshd - install -cs -o bin $? $@ + install -cs -o bin $< $@ /bin/install: installx - install -cs -o root -m 4755 $? $@ + install -cs -o root -m 4755 $< $@ /usr/bin/install: installx - install -cs -o root -m 4755 $? $@ + install -cs -o root -m 4755 $< $@ /usr/bin/intr: intr - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/irdpd: irdpd - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/isoread: isoread - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/isodir /usr/bin/isoinfo: /usr/bin/isoread - install -l $? $@ + install -l $< $@ /usr/bin/join: join - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/kill: kill - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/last: last - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/uptime: /usr/bin/last - install -l $? $@ + install -l $< $@ /usr/bin/leave: leave - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/life: life - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/loadramdisk: loadramdisk - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/login: login - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/look: look - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/lp: lp - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/lpd: lpd - install -cs -o daemon -m 4755 $? $@ + install -cs -o daemon -m 4755 $< $@ /usr/bin/ls: ls - install -cs -o bin $? $@ + install -cs -o bin $< $@ /bin/ls: ls - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/mail: mail - install -cs -o root -m 4755 $? $@ + install -cs -o root -m 4755 $< $@ /usr/bin/man: man - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/mesg: mesg - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/mkdir: mkdir - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/mkfifo: mkfifo - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/mkfs: mkfs - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/mknod: mknod - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/mkproto: mkproto - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/mkswap: mkswap - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/modem: modem - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/mount: mount - install -cs -o root -m 4755 $? $@ + install -cs -o root -m 4755 $< $@ /usr/bin/mt: mt - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/newroot: newroot - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/nm: nm - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/nice: nice - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/nonamed: nonamed - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/od: od - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/passwd: passwd - install -cs -o root -m 4755 $? $@ + install -cs -o root -m 4755 $< $@ /usr/bin/chfn /usr/bin/chsh: /usr/bin/passwd - install -l $? $@ + install -l $< $@ /usr/bin/paste: paste - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/ping: ping - install -cs -o root -m 4755 $? $@ + install -cs -o root -m 4755 $< $@ /usr/bin/pr: pr - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/pr_routes: pr_routes - install -cs -o root -m 4755 $? $@ + install -cs -o root -m 4755 $< $@ /usr/bin/progressbar: progressbar - install -cs -o root -m 755 $? $@ + install -cs -o root -m 755 $< $@ /usr/bin/prep: prep - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/printf: printf - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/printenv: printenv - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/printroot: printroot - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/proto: proto - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/pwd: pwd - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/lib/pwdauth: pwdauth - install -cs -o root -m 4755 $? $@ + install -cs -o root -m 4755 $< $@ /usr/bin/ramdisk: ramdisk - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/rarpd: rarpd - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/rcp: rcp - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/rawspeed: rawspeed - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/rdate: rdate - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/readall: readall - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/readlink: /usr/bin/stat - install -l $? $@ + install -l $< $@ /usr/bin/readfs: readfs - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/remsync: remsync - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/rev: rev - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/rget: rget - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/rput: /usr/bin/rget - install -l $? $@ + install -l $< $@ /usr/bin/rlogin: rlogin - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/rmdir: rmdir - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/rsh: rsh - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/sed: sed - install -cs -o bin $? $@ + install -cs -o bin $< $@ /bin/sed: sed - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/shar: shar - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/size: size - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/sleep: sleep - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/slip: slip - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/sort: sort - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/split: split - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/stat: stat - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/fstat: /usr/bin/stat - install -l $? $@ + install -l $< $@ /usr/bin/strings: strings - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/strip: strip - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/stty: stty - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/su: su - install -cs -o root -m 4755 $? $@ + install -cs -o root -m 4755 $< $@ /usr/bin/sum: sum - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/swapfs: swapfs - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/sync: sync - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/synctree: synctree - install -cs -o bin $? $@ + install -cs -o bin $< $@ /bin/sysenv: sysenv - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/sysenv: sysenv - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/tail: tail - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/tar: tar - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/tcpd: tcpd - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/tcpdp: tcpdp - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/tcpstat: tcpstat - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/tee: tee - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/term: term - install -cs -o bin -g uucp -m 2755 $? $@ + install -cs -o bin -g uucp -m 2755 $< $@ /usr/bin/termcap: termcap - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/tget: tget - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/time: time - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/top: top - install -cs -o root -m 4755 $? $@ + install -cs -o root -m 4755 $< $@ /usr/bin/touch: touch - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/tr: tr - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/treecmp: treecmp - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/truncate: truncate - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/tsort: tsort - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/ttt: ttt - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/tty: tty - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/udpstat: udpstat - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/umount: umount - install -cs -o root -m 4755 $? $@ + install -cs -o root -m 4755 $< $@ /usr/bin/uname: uname - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/arch: /usr/bin/uname - install -l $? $@ + install -l $< $@ /usr/bin/unexpand: unexpand - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/uniq: uniq - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/update: update - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/uud: uud - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/uudecode: /usr/bin/uud - install -l $? $@ + install -l $< $@ /usr/bin/uue: uue - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/uuencode: /usr/bin/uue - install -l $? $@ + install -l $< $@ /usr/bin/vol: vol - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/wc: wc - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/which: which - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/who: who - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/whoami: whoami - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/write: write - install -cs -o bin -g tty -m 2755 $? $@ + install -cs -o bin -g tty -m 2755 $< $@ /usr/bin/writeisofs: writeisofs - install -cs -S 2M -o bin $? $@ + install -cs -S 2M -o bin $< $@ /usr/bin/xargs: xargs - install -cs -o bin $? $@ + install -cs -o bin $< $@ /usr/bin/yes: yes - install -cs -o bin $? $@ + install -cs -o bin $< $@ /bin/cat: /usr/bin/cat - install -lcs $? $@ + install -lcs $< $@ /bin/fsck: /usr/bin/fsck - install -lcs $? $@ + install -lcs $< $@ /bin/intr: /usr/bin/intr - install -lcs $? $@ + install -lcs $< $@ /bin/mount: /usr/bin/mount - install -lcs $? $@ + install -lcs $< $@ /bin/printroot: /usr/bin/printroot - install -lcs $? $@ + install -lcs $< $@ /bin/pwd: /usr/bin/pwd - install -lcs $? $@ + install -lcs $< $@ /bin/sync: /usr/bin/sync - install -lcs $? $@ + install -lcs $< $@ /bin/umount: /usr/bin/umount - install -lcs $? $@ + install -lcs $< $@ clean: rm -rf $(ALL) a.out core diff --git a/commands/simple/last.c b/commands/simple/last.c index 74124b052..80b085bf9 100755 --- a/commands/simple/last.c +++ b/commands/simple/last.c @@ -479,3 +479,4 @@ char *argv[]; printf("\nwtmp begins %.16s \n", ctime(&wtmp_buffer[0].ut_time)); return(0); } + diff --git a/commands/simple/mkfs.c b/commands/simple/mkfs.c index faddeb51d..ef29539ca 100755 --- a/commands/simple/mkfs.c +++ b/commands/simple/mkfs.c @@ -56,17 +56,8 @@ #define BIN 2 #define BINGRP 2 #define BIT_MAP_SHIFT 13 -#define N_BLOCKS MAX_BLOCK_NR -#define N_BLOCKS16 (128L * 1024) #define INODE_MAX ((unsigned) 65535) -/* You can make a really large file system on a 16-bit system, but the array - * of bits that get_block()/putblock() needs gets a bit big, so we can only - * prefill MAX_INIT blocks. (16-bit fsck can't check a file system larger - * than N_BLOCKS16 anyway.) - */ -#define MAX_INIT (sizeof(char *) == 2 ? N_BLOCKS16 : N_BLOCKS) - #ifdef DOS maybedefine O_RDONLY 4 /* O_RDONLY | BINARY_BIT */ @@ -90,12 +81,12 @@ char *progname; long current_time, bin_time; char *zero, *lastp; -char umap[MAX_INIT / 8]; /* bit map tells if block read yet */ +char *umap_array; /* bit map tells if block read yet */ +int umap_array_elements = 0; block_t zone_map; /* where is zone map? (depends on # inodes) */ int inodes_per_block; int fs_version; unsigned int block_size; -block_t max_nrblocks; FILE *proto; @@ -167,14 +158,12 @@ char *argv[]; i = 0; fs_version = 3; inodes_per_block = 0; - max_nrblocks = N_BLOCKS; block_size = 0; while ((ch = getopt(argc, argv, "12b:di:lotB:")) != EOF) switch (ch) { case '1': fs_version = 1; inodes_per_block = V1_INODES_PER_BLOCK; - max_nrblocks = 0xFFFF; break; case '2': fs_version = 2; @@ -262,12 +251,6 @@ char *argv[]; /* Read the line with the block and inode counts. */ getline(line, token); blocks = atol(token[0]); - if (blocks > max_nrblocks) pexit("Block count too large"); - if (sizeof(char *) == 2 && blocks > N_BLOCKS16) { - fprintf(stderr, - "%s: warning: FS is larger than the %dM that fsck can check!\n", - progname, (int) (N_BLOCKS16 / (1024L * 1024))); - } inodes = atoi(token[1]); /* Process mode line for root directory. */ @@ -305,7 +288,6 @@ char *argv[]; } if (blocks < 5) pexit("Block count too small"); - if (blocks > max_nrblocks) pexit("Block count too large"); if (i < 1) pexit("Inode count too small"); if (i > INODE_MAX && fs_version < 3) pexit("Inode count too large"); inodes = (ino_t) i; @@ -320,6 +302,17 @@ char *argv[]; nrblocks = blocks; nrinodes = inodes; +{ + size_t bytes; + bytes = 1 + blocks/8; + if(!(umap_array = malloc(bytes))) { + fprintf(stderr, "mkfs: can't allocate block bitmap (%d bytes).\n", + bytes); + exit(1); + } + umap_array_elements = bytes; +} + /* Open special. */ special(argv[--optind]); @@ -336,7 +329,7 @@ char *argv[]; } testb[0] = 0x3245; testb[1] = 0x11FF; - testb[block_size-1] = 0x1F2F; + testb[block_size/2-1] = 0x1F2F; if ((w=write(fd, (char *) testb, block_size)) != block_size) { if(w < 0) perror("write"); printf("%d/%d\n", w, block_size); @@ -350,7 +343,7 @@ char *argv[]; testb[1] = 0; nread = read(fd, (char *) testb, block_size); if (nread != block_size || testb[0] != 0x3245 || testb[1] != 0x11FF || - testb[block_size-1] != 0x1F2F) { + testb[block_size/2-1] != 0x1F2F) { if(nread < 0) perror("read"); printf("nread = %d\n", nread); printf("testb = 0x%x 0x%x 0x%x\n", testb[0], testb[1], testb[block_size-1]); @@ -370,24 +363,6 @@ printf("testb = 0x%x 0x%x 0x%x\n", testb[0], testb[1], testb[block_size-1]); cache_init(); -#if (MACHINE == ATARI) - if (isdev) { - char block0[BLOCK_SIZE]; - get_block((block_t) 0, block0); - /* Need to read twice; first time gets an empty block */ - get_block((block_t) 0, block0); - /* Zero parts of the boot block so the disk won't be - * recognized as a tos disk any more. */ - block0[0] = block0[1] = 0; /* branch code to boot code */ - strncpy(&block0[2], "MINIX ", (size_t) 6); - block0[16] = 0; /* number of FATS */ - block0[17] = block0[18] = 0; /* number of dir entries */ - block0[22] = block0[23] = 0; /* sectors/FAT */ - bzero(&block0[30], 480);/* boot code */ - put_block((block_t) 0, block0); - } else -#endif - put_block((block_t) 0, zero); /* Write a null boot block. */ zone_shift = 0; /* for future use */ @@ -1229,12 +1204,14 @@ block_t n; int w, s, mask, r; - if (sizeof(char *) == 2 && n >= MAX_INIT) pexit("can't initialize past 128M"); w = n / 8; + if(w >= umap_array_elements) { + pexit("umap array too small - this can't happen"); + } s = n % 8; mask = 1 << s; - r = (umap[w] & mask ? 1 : 0); - umap[w] |= mask; + r = (umap_array[w] & mask ? 1 : 0); + umap_array[w] |= mask; return(r); } diff --git a/commands/simple/top.c b/commands/simple/top.c index a5647ff8d..4679f4f7f 100644 --- a/commands/simple/top.c +++ b/commands/simple/top.c @@ -40,6 +40,7 @@ char *Tclr_all; +#if 0 int print_memory(struct pm_mem_info *pmi) { int h; @@ -58,6 +59,7 @@ int print_memory(struct pm_mem_info *pmi) return 1; } +#endif int print_load(double *loads, int nloads) { @@ -209,10 +211,13 @@ void showtop(int r) int nloads, i, p, lines = 0; static struct proc prev_proc[PROCS], proc[PROCS]; struct winsize winsize; - static struct pm_mem_info pmi; + /* + static struct pm_mem_info pmi; + */ static int prev_uptime, uptime; static struct mproc mproc[NR_PROCS]; struct tms tms; + int mem = 0; uptime = times(&tms); @@ -222,10 +227,13 @@ void showtop(int r) exit(1); } +#if 0 if(getsysinfo(PM_PROC_NR, SI_MEM_ALLOC, &pmi) < 0) { fprintf(stderr, "getsysinfo() for SI_MEM_ALLOC failed.\n"); + mem = 0; exit(1);; - } + } else mem = 1; +#endif if(getsysinfo(PM_PROC_NR, SI_KPROC_TAB, proc) < 0) { fprintf(stderr, "getsysinfo() for SI_KPROC_TAB failed.\n"); @@ -247,7 +255,9 @@ void showtop(int r) lines += print_load(loads, NLOADS); lines += print_proc_summary(proc); - lines += print_memory(&pmi); +#if 0 + if(mem) { lines += print_memory(&pmi); } +#endif if(winsize.ws_row > 0) r = winsize.ws_row; @@ -347,3 +357,4 @@ int main(int argc, char *argv[]) return 0; } +int sys_hz() { return 50; } diff --git a/commands/syslogd/Makefile b/commands/syslogd/Makefile index 66094bb24..c34a13d55 100644 --- a/commands/syslogd/Makefile +++ b/commands/syslogd/Makefile @@ -22,7 +22,7 @@ all: $(TARGETS) syslogd: syslogd.o $(CC) $? $(LDFLAGS) - @install -S 8kw $@ + @install $@ syslog_test: syslog_test.o syslog.o $(CC) syslog_test.o syslog.o $(LDFLAGS) diff --git a/drivers/amddev/Makefile b/drivers/amddev/Makefile index 85abf1d5a..c231b2b55 100644 --- a/drivers/amddev/Makefile +++ b/drivers/amddev/Makefile @@ -5,8 +5,7 @@ DRIVER = amddev CC = exec cc CFLAGS = $(CPROFILE) LDFLAGS = -i -#LIBS = -lsysutil -lsys -ltimers -LIBS = -lsysutil -lsys +LIBS = -lsys OBJ = amddev.o diff --git a/drivers/amddev/amddev.c b/drivers/amddev/amddev.c index fe011a9c6..1491af553 100644 --- a/drivers/amddev/amddev.c +++ b/drivers/amddev/amddev.c @@ -15,7 +15,7 @@ Driver for the AMD Device Exclusion Vector (DEV) #include #include #include -#include +#include #include #include #include @@ -213,17 +213,13 @@ static void write_reg(int function, int index, u32_t value) static void init_domain(int index) { - int r; size_t o, size, memsize; phys_bytes busaddr; size= 0x100000 / 8; - table= malloc(size + PAGE_SIZE); + table= alloc_contig(size, AC_ALIGN4K, &busaddr); if (table == NULL) panic("AMDDEV","malloc failed", NO_NUM); - o= (unsigned)table & (PAGE_SIZE-1); - if (o) - table += PAGE_SIZE-o; if (index == 0) { memset(table, 0, size); @@ -237,9 +233,6 @@ static void init_domain(int index) memset(table, 0x00, size); } - r= sys_umap(SELF, D, (vir_bytes)table, size, &busaddr); - if (r != OK) - panic("AMDDEV","sys_umap failed", r); printf("init_domain: busaddr = %p\n", busaddr); write_reg(DEVF_BASE_HI, index, 0); @@ -265,6 +258,7 @@ static void init_map(int index) printf("after write: DEVF_MAP: 0x%x\n", read_reg(DEVF_MAP, index)); } +#if 0 static int do_add(message *m) { int r; @@ -282,19 +276,19 @@ static int do_add(message *m) size, start, proc); #endif - if (start % PAGE_SIZE) + if (start % I386_PAGE_SIZE) { printf("amddev`do_add: bad start 0x%x from proc %d\n", start, proc); return EINVAL; } - if (size % PAGE_SIZE) + if (size % I386_PAGE_SIZE) { printf("amddev`do_add: bad size 0x%x from proc %d\n", size, proc); return EINVAL; } - r= sys_umap(proc, D, (vir_bytes)start, size, &busaddr); + r= sys_umap(proc, VM_D, (vir_bytes)start, size, &busaddr); if (r != OK) { printf("amddev`do_add: umap failed for 0x%x@0x%x, proc %d\n", @@ -304,6 +298,7 @@ static int do_add(message *m) add_range(busaddr, size); } +#endif static int do_add_phys(message *m) { @@ -319,12 +314,12 @@ static int do_add_phys(message *m) size, start); #endif - if (start % PAGE_SIZE) + if (start % I386_PAGE_SIZE) { printf("amddev`do_add_phys: bad start 0x%x\n", start); return EINVAL; } - if (size % PAGE_SIZE) + if (size % I386_PAGE_SIZE) { printf("amddev`do_add_phys: bad size 0x%x\n", size); return EINVAL; @@ -355,12 +350,12 @@ static int do_del_phys(message *m) size, start); #endif - if (start % PAGE_SIZE) + if (start % I386_PAGE_SIZE) { printf("amddev`do_del_phys: bad start 0x%x\n", start); return EINVAL; } - if (size % PAGE_SIZE) + if (size % I386_PAGE_SIZE) { printf("amddev`do_del_phys: bad size 0x%x\n", size); return EINVAL; @@ -391,13 +386,13 @@ static int do_add4pci(message *m) "amddev`do_add4pci: got request for 0x%x@0x%x from %d for pci dev %u.%u.%u\n", size, start, proc, pci_bus, pci_dev, pci_func); - if (start % PAGE_SIZE) + if (start % I386_PAGE_SIZE) { printf("amddev`do_add4pci: bad start 0x%x from proc %d\n", start, proc); return EINVAL; } - if (size % PAGE_SIZE) + if (size % I386_PAGE_SIZE) { printf("amddev`do_add4pci: bad size 0x%x from proc %d\n", size, proc); @@ -406,7 +401,7 @@ static int do_add4pci(message *m) printf("amddev`do_add4pci: should check with PCI\n"); - r= sys_umap(proc, D, (vir_bytes)start, size, &busaddr); + r= sys_umap(proc, VM_D, (vir_bytes)start, size, &busaddr); if (r != OK) { printf( @@ -415,7 +410,7 @@ static int do_add4pci(message *m) return r; } - r= adddma(proc, busaddr, size); + r= adddma(proc, start, size); if (r != 0) { r= -errno; @@ -439,9 +434,9 @@ static void add_range(u32_t busaddr, u32_t size) printf("add_range: mapping 0x%x@0x%x\n", size, busaddr); #endif - for (o= 0; o #include +#include #include #include +#include #define ATAPI_DEBUG 0 /* To debug ATAPI code. */ @@ -294,7 +296,6 @@ PRIVATE struct wini { /* main drive struct, one entry per drive */ PRIVATE int w_device = -1; PRIVATE int w_controller = -1; PRIVATE int w_major = -1; -PRIVATE char w_id_string[40]; PRIVATE int win_tasknr; /* my task number */ PRIVATE int w_command; /* current command in execution */ @@ -309,7 +310,7 @@ PRIVATE struct device *w_dv; /* device's base and size */ #define ATA_DMA_SECTORS 64 #define ATA_DMA_BUF_SIZE (ATA_DMA_SECTORS*SECTOR_SIZE) -PRIVATE char dma_buf[ATA_DMA_BUF_SIZE]; +PRIVATE char *dma_buf; PRIVATE phys_bytes dma_buf_phys; #define N_PRDTE 1024 /* Should be enough for large requests */ @@ -320,7 +321,10 @@ PRIVATE struct prdte u16_t prdte_count; u8_t prdte_reserved; u8_t prdte_flags; -} prdt[N_PRDTE]; +}; + +#define PRDT_BYTES (sizeof(struct prdte) * N_PRDTE) +PRIVATE struct prdte *prdt; PRIVATE phys_bytes prdt_phys; #define PRDTE_FL_EOT 0x80 /* End of table */ @@ -428,6 +432,8 @@ PUBLIC int main(int argc, char *argv[]) /* Install signal handlers. Ask PM to transform signal into message. */ struct sigaction sa; + init_buffer(); + sa.sa_handler = SIG_MESS; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; @@ -475,16 +481,34 @@ PRIVATE void init_params() w_identify_wakeup_ticks = WAKEUP_TICKS; } - if (disable_dma) - printf("DMA for ATA devices is disabled.\n"); + if (disable_dma) { + printf("at_wini%d: DMA for ATA devices is disabled.\n", w_instance); + } else { + /* Ask for anonymous memory for DMA, that is physically contiguous. */ + dma_buf = mmap(0, ATA_DMA_BUF_SIZE, PROT_READ|PROT_WRITE, + MAP_PREALLOC | MAP_CONTIG | MAP_ANON, -1, 0); + prdt = mmap(0, PRDT_BYTES, + PROT_READ|PROT_WRITE, MAP_CONTIG | MAP_ANON, -1, 0); + if(dma_buf == MAP_FAILED || prdt == MAP_FAILED) { + disable_dma = 1; + printf("at_wini%d: no dma\n", w_instance); + } else { + s= sys_umap(SELF, VM_D, (vir_bytes)dma_buf, + ATA_DMA_BUF_SIZE, &dma_buf_phys); + if (s != 0) + panic("at_wini", "can't map dma buffer", s); - s= sys_umap(SELF, D, (vir_bytes)dma_buf, sizeof(dma_buf), &dma_buf_phys); - if (s != 0) - panic("at_wini", "can't map dma buffer", s); - - s= sys_umap(SELF, D, (vir_bytes)prdt, sizeof(prdt), &prdt_phys); - if (s != 0) - panic("at_wini", "can't map prd table", s); + s= sys_umap(SELF, VM_D, (vir_bytes)prdt, + PRDT_BYTES, &prdt_phys); + if (s != 0) + panic("at_wini", "can't map prd table", s); +#if 0 + printf("at_wini%d: physical dma_buf: 0x%lx, " + "prdt tab: 0x%lx\n", + w_instance, dma_buf_phys, prdt_phys); +#endif + } + } if (w_instance == 0) { /* Get the number of drives from the BIOS data area */ @@ -524,7 +548,7 @@ PRIVATE void init_params() 0 /* no DMA */, NO_IRQ, 0, 0, drive); w_next_drive++; } - } + } /* Look for controllers on the pci bus. Skip none the first instance, * skip one and then 2 for every instance, for every next instance. @@ -779,15 +803,6 @@ message *m_ptr; wn->state |= IGNORING; return(ENXIO); } - -#if VERBOSE - printf("%s: AT driver detected ", w_name()); - if (wn->state & (SMART|ATAPI)) { - printf("%.40s\n", w_id_string); - } else { - printf("%ux%ux%u\n", wn->pcylinders, wn->pheads, wn->psectors); - } -#endif } #if ENABLE_ATAPI @@ -898,9 +913,6 @@ PRIVATE int w_identify() /* This is an ATA device. */ wn->state |= SMART; - /* Why are the strings byte swapped??? */ - for (i = 0; i < 40; i++) w_id_string[i] = id_byte(27)[i^1]; - /* Preferred CHS translation mode. */ wn->pcylinders = id_word(1); wn->pheads = id_word(3); @@ -958,7 +970,8 @@ PRIVATE int w_identify() else if (id_dma && dma_base) { w= id_word(ID_MULTIWORD_DMA); - if (w & (ID_MWDMA_2_SUP|ID_MWDMA_1_SUP|ID_MWDMA_0_SUP)) + if (w_pci_debug && + (w & (ID_MWDMA_2_SUP|ID_MWDMA_1_SUP|ID_MWDMA_0_SUP))) { printf( "%s: multiword DMA modes supported:%s%s%s\n", @@ -967,7 +980,8 @@ PRIVATE int w_identify() (w & ID_MWDMA_1_SUP) ? " 1" : "", (w & ID_MWDMA_2_SUP) ? " 2" : ""); } - if (w & (ID_MWDMA_0_SEL|ID_MWDMA_1_SEL|ID_MWDMA_2_SEL)) + if (w_pci_debug && + (w & (ID_MWDMA_0_SEL|ID_MWDMA_1_SEL|ID_MWDMA_2_SEL))) { printf( "%s: multiword DMA mode selected:%s%s%s\n", @@ -976,7 +990,7 @@ PRIVATE int w_identify() (w & ID_MWDMA_1_SEL) ? " 1" : "", (w & ID_MWDMA_2_SEL) ? " 2" : ""); } - if (ultra_dma) + if (w_pci_debug && ultra_dma) { w= id_word(ID_ULTRA_DMA); if (w & (ID_UDMA_0_SUP|ID_UDMA_1_SUP| @@ -1048,9 +1062,6 @@ PRIVATE int w_identify() if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, 512)) != OK) panic(w_name(),"Call to sys_insw() failed", s); - /* Why are the strings byte swapped??? */ - for (i = 0; i < 40; i++) w_id_string[i] = id_byte(27)[i^1]; - size = 0; /* Size set later. */ #endif } else { @@ -1114,14 +1125,17 @@ PRIVATE int w_io_test(void) int r, save_dev; int save_timeout, save_errors, save_wakeup; iovec_t iov; + static char *buf; + #ifdef CD_SECTOR_SIZE - static char buf[CD_SECTOR_SIZE]; +#define BUFSIZE CD_SECTOR_SIZE #else - static char buf[SECTOR_SIZE]; +#define BUFSIZE SECTOR_SIZE #endif + STATICINIT(buf, BUFSIZE); iov.iov_addr = (vir_bytes) buf; - iov.iov_size = sizeof(buf); + iov.iov_size = BUFSIZE; save_dev = w_device; /* Reduce timeout values for this test transaction. */ @@ -1321,8 +1335,8 @@ int safe; /* iov contains addresses (0) or grants? */ nbytes = diff64(dv_size, position); block = div64u(add64(w_dv->dv_base, position), SECTOR_SIZE); - do_dma= wn->dma; do_write= (opcode == DEV_SCATTER_S); + do_dma= wn->dma; if (nbytes >= wn->max_count) { /* The drive can't do more then max_count at once. */ @@ -1475,14 +1489,17 @@ int safe; /* iov contains addresses (0) or grants? */ s=sys_safe_insw(wn->base_cmd + REG_DATA, proc_nr, (void *) (iov->iov_addr), addr_offset, SECTOR_SIZE); + if(s != OK) { + panic(w_name(),"Call to sys_safe_insw() failed", s); + } } else { s=sys_insw(wn->base_cmd + REG_DATA, proc_nr, (void *) (iov->iov_addr + addr_offset), SECTOR_SIZE); - } if(s != OK) { panic(w_name(),"Call to sys_insw() failed", s); } + } } else { if(safe) { s=sys_safe_outsw(wn->base_cmd + REG_DATA, proc_nr, @@ -1662,14 +1679,14 @@ int safe; offset= 0; /* Offset in current iov */ #if 0 - printf("setup_dma: proc_nr %d\n", proc_nr); + printf("at_wini: setup_dma: proc_nr %d\n", proc_nr); #endif while (size > 0) { #if 0 printf( - "setup_dma: iov[%d]: addr 0x%x, size %d offset %d, size %d\n", + "at_wini: setup_dma: iov[%d]: addr 0x%x, size %d offset %d, size %d\n", i, iov[i].iov_addr, iov[i].iov_size, offset, size); #endif @@ -1679,13 +1696,15 @@ int safe; if (n == 0 || (n & 1)) panic("at_wini", "bad size in iov", iov[i].iov_size); if(safe) { - r= sys_umap(proc_nr, GRANT_SEG, iov[i].iov_addr, n,&user_phys); + r= sys_umap(proc_nr, VM_GRANT, iov[i].iov_addr, n,&user_phys); + if (r != 0) + panic("at_wini", "can't map user buffer (VM_GRANT)", r); user_phys += offset; } else { - r= sys_umap(proc_nr, D, iov[i].iov_addr+offset, n, &user_phys); - } + r= sys_umap(proc_nr, VM_D, iov[i].iov_addr+offset, n, &user_phys); if (r != 0) - panic("at_wini", "can't map user buffer", r); + panic("at_wini", "can't map user buffer (VM_D)", r); + } if (user_phys & 1) { /* Buffer is not aligned */ @@ -2709,7 +2728,7 @@ PRIVATE int at_in(int line, u32_t port, u32_t *value, return OK; printf("at_wini%d: line %d: %s failed: %d; port %x\n", w_instance, line, typename, s, value, port); - panic(w_name(), "sys_out failed", NO_NUM); + panic(w_name(), "sys_in failed", NO_NUM); } #undef panic diff --git a/drivers/audio/es1370/Makefile b/drivers/audio/es1370/Makefile index 579c91732..d10121df6 100644 --- a/drivers/audio/es1370/Makefile +++ b/drivers/audio/es1370/Makefile @@ -12,7 +12,7 @@ gen_drv_dir = ../../gen_drivers/cyclic_dma CC = exec cc CFLAGS = -I$i LDFLAGS = -i -LIBS = -lsys -lsysutil +LIBS = -lsys # build local binary all: es1370 diff --git a/drivers/audio/es1371/Makefile b/drivers/audio/es1371/Makefile index 309ad0468..ae7d5faf1 100755 --- a/drivers/audio/es1371/Makefile +++ b/drivers/audio/es1371/Makefile @@ -11,7 +11,7 @@ b = $i/ibm CC = exec cc CFLAGS = -I$i LDFLAGS = -i -LIBS = -lsys -lsysutil +LIBS = -lsys PROGRAM_NAME = es1371 INSTALL_BIN = /usr/sbin/$(PROGRAM_NAME) diff --git a/drivers/audio/framework/audio_fw.c b/drivers/audio/framework/audio_fw.c index de2590798..38d8e6cdb 100755 --- a/drivers/audio/framework/audio_fw.c +++ b/drivers/audio/framework/audio_fw.c @@ -45,6 +45,7 @@ #include "audio_fw.h" #include #include +#include FORWARD _PROTOTYPE( int msg_open, (int minor_dev_nr) ); @@ -85,7 +86,6 @@ PUBLIC void main(void) /* Here is the main loop of the dma driver. It waits for a message, carries it out, and sends a reply. */ - printf("%s up and running\n", drv.DriverName); while(1) { receive(ANY, &mess); @@ -886,19 +886,16 @@ PRIVATE int init_buffers(sub_dev_t *sub_dev_ptr) size_t size, off; unsigned left; u32_t i; + phys_bytes ph; /* allocate dma buffer space */ size= sub_dev_ptr->DmaSize + 64 * 1024; - base= malloc(size + PAGE_SIZE); + off = base= alloc_contig(size, AC_ALIGN4K, &ph); if (!base) { error("%s: failed to allocate dma buffer for channel %d\n", drv.DriverName,i); return EIO; } - /* Align base */ - off= ((size_t)base % PAGE_SIZE); - if (off) - base += PAGE_SIZE-off; sub_dev_ptr->DmaBuf= base; tell_dev((vir_bytes)base, size, 0, 0, 0); diff --git a/drivers/audio/sb16/Makefile b/drivers/audio/sb16/Makefile index cdb52e42f..2b2591f33 100755 --- a/drivers/audio/sb16/Makefile +++ b/drivers/audio/sb16/Makefile @@ -12,7 +12,7 @@ d = .. CC = exec cc CFLAGS = -I$i LDFLAGS = -i -LIBS = -lsys -lsysutil +LIBS = -lsys # build local binary diff --git a/drivers/bios_wini/Makefile b/drivers/bios_wini/Makefile index daf107dca..5b6888b8a 100644 --- a/drivers/bios_wini/Makefile +++ b/drivers/bios_wini/Makefile @@ -14,7 +14,7 @@ MAKE = exec make CC = exec cc CFLAGS = -I$i $(CPROFILE) LDFLAGS = -i -L../libdriver -LIBS = -lsysutil -lsys -ltimers -ldriver +LIBS = -ldriver -lsys -lsys -ltimers OBJ = bios_wini.o diff --git a/drivers/bios_wini/bios_wini.c b/drivers/bios_wini/bios_wini.c index 87d6fd2fd..98dcecf58 100644 --- a/drivers/bios_wini/bios_wini.c +++ b/drivers/bios_wini/bios_wini.c @@ -166,7 +166,7 @@ vir_bytes from_vir; endpoint_t to_proc; int to_seg; vir_bytes to_vir; -vir_bytes grant_offset; +size_t grant_offset; size_t size; { phys_bytes addr; diff --git a/drivers/dp8390/Makefile b/drivers/dp8390/Makefile index 87d2ae91c..08a02c1b1 100644 --- a/drivers/dp8390/Makefile +++ b/drivers/dp8390/Makefile @@ -13,7 +13,7 @@ d = .. CC = exec cc CFLAGS = -I$i $(CPROFILE) LDFLAGS = -i -LIBS = -lsysutil -lsys -ltimers +LIBS = -lsys -ltimers OBJ = 3c503.o dp8390.o ne2000.o rtl8029.o wdeth.o diff --git a/drivers/dp8390/dp8390.c b/drivers/dp8390/dp8390.c index 4f62de524..479e421e9 100644 --- a/drivers/dp8390/dp8390.c +++ b/drivers/dp8390/dp8390.c @@ -59,6 +59,7 @@ #include #include #include +#include #include #include "assert.h" @@ -2540,18 +2541,22 @@ dpeth_t *dep; return; } - size = dep->de_ramsize + PAGE_SIZE; /* Add PAGE_SIZE for + size = dep->de_ramsize + I386_PAGE_SIZE; /* Add I386_PAGE_SIZE for * alignment */ buf= malloc(size); if (buf == NULL) panic(__FILE__, "map_hw_buffer: cannot malloc size", size); - o= PAGE_SIZE - ((vir_bytes)buf % PAGE_SIZE); + o= I386_PAGE_SIZE - ((vir_bytes)buf % I386_PAGE_SIZE); abuf= buf + o; printf("buf at 0x%x, abuf at 0x%x\n", buf, abuf); +#if 0 r= sys_vm_map(SELF, 1 /* map */, (vir_bytes)abuf, dep->de_ramsize, (phys_bytes)dep->de_linmem); +#else + r = ENOSYS; +#endif if (r != OK) panic(__FILE__, "map_hw_buffer: sys_vm_map failed", r); dep->de_locmem = abuf; diff --git a/drivers/dpeth/Makefile b/drivers/dpeth/Makefile index 726c527cb..81f9db26a 100644 --- a/drivers/dpeth/Makefile +++ b/drivers/dpeth/Makefile @@ -15,7 +15,7 @@ LDFLAGS = -i -o $@ SRCS = 3c501.c 3c509.c 3c503.c ne.c wd.c 8390.c devio.c netbuff.c dp.c OBJS = 3c501.o 3c509.o 3c503.o ne.o wd.o 8390.o devio.o netbuff.o dp.o -LIBS = -lsysutil -lsys # -ltimers +LIBS = -lsys ## Build rules all build: $(DRIVER) diff --git a/drivers/floppy/Makefile b/drivers/floppy/Makefile index 397de8c19..478dde0de 100644 --- a/drivers/floppy/Makefile +++ b/drivers/floppy/Makefile @@ -14,7 +14,7 @@ MAKE = exec make CC = exec cc CFLAGS = -I$i $(CPROFILE) LDFLAGS = -i -L../libdriver -LIBS = -lsysutil -ldriver -lsys -ltimers +LIBS = -ldriver -lsys -ltimers OBJ = floppy.o diff --git a/drivers/floppy/floppy.c b/drivers/floppy/floppy.c index f21c4de7b..b1ed29c26 100644 --- a/drivers/floppy/floppy.c +++ b/drivers/floppy/floppy.c @@ -294,6 +294,8 @@ PUBLIC void main() struct floppy *fp; int s; + init_buffer(); + f_next_timeout = TMR_NEVER; tmr_inittimer(&f_tmr_timeout); diff --git a/drivers/fxp/Makefile b/drivers/fxp/Makefile index ee795c322..3850d3502 100644 --- a/drivers/fxp/Makefile +++ b/drivers/fxp/Makefile @@ -13,7 +13,7 @@ d = .. CC = exec cc CFLAGS = -I$i $(CPROFILE) LDFLAGS = -i -LIBS = -lsysutil -lsys -ltimers +LIBS = -lsys -ltimers OBJ = fxp.o mii.o @@ -21,7 +21,7 @@ OBJ = fxp.o mii.o all build: $(DRIVER) $(DRIVER): $(OBJ) $(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS) - install -S 96k $(DRIVER) + install -S 128k $(DRIVER) # install with other drivers install: /usr/sbin/$(DRIVER) diff --git a/drivers/fxp/fxp.c b/drivers/fxp/fxp.c index fb76cd515..1a146f139 100644 --- a/drivers/fxp/fxp.c +++ b/drivers/fxp/fxp.c @@ -211,7 +211,8 @@ fxp_t; #define FT_82558A 0x2 #define FT_82559 0x4 -static fxp_t fxp_table[FXP_PORT_NR]; +static fxp_t *fxp_table; +phys_bytes fxp_table_phys; static u16_t eth_ign_proto; static tmra_ut fxp_watchdog; @@ -281,6 +282,7 @@ int main(int argc, char *argv[]) u32_t tasknr; fxp_t *fp; long v; + vir_bytes ft = sizeof(*fxp_table)*FXP_PORT_NR; if (argc < 1) panic("FXP", "A head which at this time has no name", NO_NUM); @@ -292,6 +294,11 @@ int main(int argc, char *argv[]) #endif eth_ign_proto= htons((u16_t) v); + if(!(fxp_table = alloc_contig(ft, 0, &fxp_table_phys))) + panic("FXP","couldn't allocate table", r); + + memset(fxp_table, 0, ft); + if((r=micro_delay_calibrate()) != OK) panic("FXP","rmicro_delay_calibrate failed", r); @@ -795,7 +802,7 @@ fxp_t *fp; fxp_do_conf(fp); /* Set pointer to statistical counters */ - r= sys_umap(SELF, D, (vir_bytes)&fp->fxp_stat, sizeof(fp->fxp_stat), + r= sys_umap(SELF, VM_D, (vir_bytes)&fp->fxp_stat, sizeof(fp->fxp_stat), &bus_addr); if (r != OK) panic("FXP","sys_umap failed", r); @@ -835,6 +842,7 @@ fxp_t *fp; int i, r; struct rfd *rfdp; struct tx *txp; + phys_bytes ph; fp->fxp_rx_nbuf= N_RX_BUF; rx_totbufsize= fp->fxp_rx_nbuf * sizeof(struct rfd); @@ -844,33 +852,33 @@ fxp_t *fp; tx_totbufsize= fp->fxp_tx_nbuf * sizeof(struct tx); fp->fxp_tx_bufsize= tx_totbufsize; -#define BUFALIGN 4096 tot_bufsize= sizeof(*tmpbufp) + tx_totbufsize + rx_totbufsize; if (tot_bufsize % 4096) tot_bufsize += 4096 - (tot_bufsize % 4096); - alloc_bufsize= tot_bufsize+BUFALIGN; - alloc_buf= malloc(alloc_bufsize); + alloc_bufsize= tot_bufsize; + alloc_buf= alloc_contig(alloc_bufsize, AC_ALIGN4K, &ph); if (alloc_buf == NULL) { - panic(__FILE__, "fxp_init_buf: unable to malloc size", + panic(__FILE__, "fxp_init_buf: unable to alloc_contig size", alloc_bufsize); } buf= (phys_bytes)alloc_buf; - buf += BUFALIGN - (buf % BUFALIGN); tell_dev((vir_bytes)buf, tot_bufsize, 0, 0, 0); tmpbufp= (union tmpbuf *)buf; fp->fxp_rx_buf= (struct rfd *)&tmpbufp[1]; - r= sys_umap(SELF, D, (vir_bytes)fp->fxp_rx_buf, rx_totbufsize, + r= sys_umap(SELF, VM_D, (vir_bytes)fp->fxp_rx_buf, rx_totbufsize, &fp->fxp_rx_busaddr); if (r != OK) panic("FXP","sys_umap failed", r); +#if 0 printf("fxp_init_buf: got phys 0x%x for vir 0x%x\n", fp->fxp_rx_busaddr, fp->fxp_rx_buf); +#endif for (i= 0, rfdp= fp->fxp_rx_buf; ifxp_rx_nbuf; i++, rfdp++) { @@ -878,7 +886,7 @@ fxp_t *fp; rfdp->rfd_command= 0; if (i != fp->fxp_rx_nbuf-1) { - r= sys_umap(SELF, D, (vir_bytes)&rfdp[1], + r= sys_umap(SELF, VM_D, (vir_bytes)&rfdp[1], sizeof(rfdp[1]), &rfdp->rfd_linkaddr); if (r != OK) panic("FXP","sys_umap failed", r); @@ -896,7 +904,7 @@ fxp_t *fp; fp->fxp_rx_head= 0; fp->fxp_tx_buf= (struct tx *)((char *)fp->fxp_rx_buf+rx_totbufsize); - r= sys_umap(SELF, D, (vir_bytes)fp->fxp_tx_buf, + r= sys_umap(SELF, VM_D, (vir_bytes)fp->fxp_tx_buf, (phys_bytes)tx_totbufsize, &fp->fxp_tx_busaddr); if (r != OK) panic("FXP","sys_umap failed", r); @@ -907,7 +915,7 @@ fxp_t *fp; txp->tx_command= TXC_EL | CBL_NOP; /* Just in case */ if (i != fp->fxp_tx_nbuf-1) { - r= sys_umap(SELF, D, (vir_bytes)&txp[1], + r= sys_umap(SELF, VM_D, (vir_bytes)&txp[1], (phys_bytes)sizeof(txp[1]), &txp->tx_linkaddr); if (r != OK) @@ -938,7 +946,7 @@ fxp_t *fp; /* Reset device */ fxp_outl(port, CSR_PORT, CP_CMD_SOFT_RESET); - tickdelay(MICROS_TO_TICKS(CSR_PORT_RESET_DELAY)); + tickdelay(micros_to_ticks(CSR_PORT_RESET_DELAY)); /* Disable interrupts */ fxp_outb(port, SCB_INT_MASK, SIM_M); @@ -995,7 +1003,7 @@ fxp_t *fp; tmpbufp->ias.ias_linkaddr= 0; memcpy(tmpbufp->ias.ias_ethaddr, fp->fxp_address.ea_addr, sizeof(tmpbufp->ias.ias_ethaddr)); - r= sys_umap(SELF, D, (vir_bytes)&tmpbufp->ias, + r= sys_umap(SELF, VM_D, (vir_bytes)&tmpbufp->ias, (phys_bytes)sizeof(tmpbufp->ias), &bus_addr); if (r != OK) panic("FXP","sys_umap failed", r); @@ -1007,7 +1015,7 @@ fxp_t *fp; /* Wait for CU command to complete */ if (tmpbufp->ias.ias_status & CBL_F_C) break; - } while (getuptime(&t1)==OK && (t1-t0) < MICROS_TO_TICKS(1000)); + } while (getuptime(&t1)==OK && (t1-t0) < micros_to_ticks(1000)); if (!(tmpbufp->ias.ias_status & CBL_F_C)) panic("FXP","fxp_confaddr: CU command failed to complete", NO_NUM); @@ -1731,7 +1739,7 @@ fxp_t *fp; memcpy(tmpbufp->cc.cc_bytes, fp->fxp_conf_bytes, sizeof(tmpbufp->cc.cc_bytes)); - r= sys_umap(SELF, D, (vir_bytes)&tmpbufp->cc, + r= sys_umap(SELF, VM_D, (vir_bytes)&tmpbufp->cc, (phys_bytes)sizeof(tmpbufp->cc), &bus_addr); if (r != OK) panic("FXP","sys_umap failed", r); @@ -1743,7 +1751,7 @@ fxp_t *fp; /* Wait for CU command to complete */ if (tmpbufp->cc.cc_status & CBL_F_C) break; - } while (getuptime(&t1)==OK && (t1-t0) < MICROS_TO_TICKS(100000)); + } while (getuptime(&t1)==OK && (t1-t0) < micros_to_ticks(100000)); if (!(tmpbufp->cc.cc_status & CBL_F_C)) panic("FXP","fxp_do_conf: CU command failed to complete", NO_NUM); @@ -1786,7 +1794,7 @@ int check_idle; scb_cmd= fxp_inb(port, SCB_CMD); if ((scb_cmd & SC_CUC_MASK) == SC_CU_NOP) break; - } while (getuptime(&t1)==OK && (t1-t0) < MICROS_TO_TICKS(100000)); + } while (getuptime(&t1)==OK && (t1-t0) < micros_to_ticks(100000)); if ((scb_cmd & SC_CUC_MASK) != SC_CU_NOP) panic("FXP","fxp_cu_ptr_cmd: CU does not accept command", NO_NUM); @@ -1823,7 +1831,7 @@ int check_idle; scb_cmd= fxp_inb(port, SCB_CMD); if ((scb_cmd & SC_RUC_MASK) == SC_RU_NOP) break; - } while (getuptime(&t1)==OK && (t1-t0) < MICROS_TO_TICKS(1000)); + } while (getuptime(&t1)==OK && (t1-t0) < micros_to_ticks(1000)); if ((scb_cmd & SC_RUC_MASK) != SC_RU_NOP) panic("FXP","fxp_ru_ptr_cmd: RU does not accept command", NO_NUM); @@ -1899,7 +1907,7 @@ message *mp; /* Wait for CU command to complete */ if (*p != 0) break; - } while (getuptime(&t1)==OK && (t1-t0) < MICROS_TO_TICKS(1000)); + } while (getuptime(&t1)==OK && (t1-t0) < micros_to_ticks(1000)); if (*p == 0) panic("FXP","fxp_getstat: CU command failed to complete", NO_NUM); @@ -1983,7 +1991,7 @@ message *mp; /* Wait for CU command to complete */ if (*p != 0) break; - } while (getuptime(&t1)==OK && (t1-t0) < MICROS_TO_TICKS(1000)); + } while (getuptime(&t1)==OK && (t1-t0) < micros_to_ticks(1000)); if (*p == 0) panic("FXP","fxp_getstat: CU command failed to complete", NO_NUM); @@ -2798,7 +2806,7 @@ int reg; v= fxp_inl(port, CSR_MDI_CTL); if (v & CM_READY) break; - } while (getuptime(&t1)==OK && (t1-t0) < MICROS_TO_TICKS(100000)); + } while (getuptime(&t1)==OK && (t1-t0) < micros_to_ticks(100000)); if (!(v & CM_READY)) panic("FXP","mii_read: MDI not ready after command", NO_NUM); @@ -2932,9 +2940,11 @@ int pci_func; r= ds_retrieve_u32("amddev", &u32); if (r != OK) { +#if 0 printf( "fxp`tell_dev: ds_retrieve_u32 failed for 'amddev': %d\n", r); +#endif return; } diff --git a/drivers/lance/Makefile b/drivers/lance/Makefile index 78ab487c1..6995bb47d 100644 --- a/drivers/lance/Makefile +++ b/drivers/lance/Makefile @@ -13,7 +13,7 @@ d = .. CC = exec cc CFLAGS = -I$i $(CPROFILE) LDFLAGS = -i -LIBS = -lsysutil -lsys +LIBS = -lsys #-lutils -ltimers OBJ = lance.o @@ -22,7 +22,7 @@ OBJ = lance.o all build: $(DRIVER) $(DRIVER): $(OBJ) $(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS) - install -S 16k $(DRIVER) + install -S 128k $(DRIVER) # install with other drivers install: /usr/sbin/$(DRIVER) diff --git a/drivers/lance/lance.c b/drivers/lance/lance.c index 1f37969e6..72401f0b1 100644 --- a/drivers/lance/lance.c +++ b/drivers/lance/lance.c @@ -193,7 +193,7 @@ unsigned long vir2phys( unsigned long x ) int r; unsigned long value; - if ( (r=sys_umap( SELF, D, x, 4, &value )) != OK ) + if ( (r=sys_umap( SELF, VM_D, x, 4, &value )) != OK ) panic( "lance", "sys_umap failed", r ); return value; @@ -202,7 +202,7 @@ unsigned long vir2phys( unsigned long x ) /* DMA limitations */ #define DMA_ADDR_MASK 0xFFFFFF /* mask to verify DMA address is 24-bit */ -#define CORRECT_DMA_MEM() ( (virt_to_bus(lance + sizeof(lance)) & ~DMA_ADDR_MASK) == 0 ) +#define CORRECT_DMA_MEM() ( (virt_to_bus(lance_buf + sizeof(struct lance_interface)) & ~DMA_ADDR_MASK) == 0 ) #define ETH_FRAME_LEN 1518 @@ -297,7 +297,8 @@ struct lance_interface /* =============== global variables =============== */ static struct lance_interface *lp; -static char lance[sizeof(struct lance_interface)+8]; +#define LANCE_BUF_SIZE (sizeof(struct lance_interface)) +static char *lance_buf = NULL; static int rx_slot_nr = 0; /* Rx-slot number */ static int tx_slot_nr = 0; /* Tx-slot number */ static int cur_tx_slot_nr = 0; /* Tx-slot number */ @@ -1682,8 +1683,11 @@ ether_card_t *ec; unsigned short ioaddr = ec->ec_port; /* ============= setup init_block(cf. lance_probe1) ================ */ - /* make sure data structure is 8-byte aligned */ - l = ((Address)lance + 7) & ~7; + /* make sure data structure is 8-byte aligned and below 16MB (for DMA) */ + assert(!lance_buf); + if(!(lance_buf = alloc_contig(LANCE_BUF_SIZE, AC_ALIGN4K|AC_LOWER16M, &l))) { + panic( "lance", "alloc_contig failed", LANCE_BUF_SIZE); + } lp = (struct lance_interface *)l; lp->init_block.mode = 0x3; /* disable Rx and Tx */ lp->init_block.filter[0] = lp->init_block.filter[1] = 0x0; diff --git a/drivers/libdriver/Makefile b/drivers/libdriver/Makefile index 534ac1a69..c88984a15 100644 --- a/drivers/libdriver/Makefile +++ b/drivers/libdriver/Makefile @@ -11,7 +11,7 @@ m = $i/minix CC = exec cc CFLAGS = -I$i $(CPROFILE) LDFLAGS = -i -LIBS = -lsysutil -lsys +LIBS = -lsys LIB = libdriver.a OBJECTS = driver.o drvlib.o mq.o diff --git a/drivers/libdriver/driver.c b/drivers/libdriver/driver.c index fe960f22f..733ffa391 100644 --- a/drivers/libdriver/driver.c +++ b/drivers/libdriver/driver.c @@ -43,29 +43,13 @@ #include #include "driver.h" -#if (CHIP == INTEL) - -#if USE_EXTRA_DMA_BUF && DMA_BUF_SIZE < 2048 -/* A bit extra scratch for the Adaptec driver. */ -#define BUF_EXTRA (2048 - DMA_BUF_SIZE) -#else -#define BUF_EXTRA 0 -#endif - /* Claim space for variables. */ -PRIVATE u8_t buffer[(unsigned) 2 * DMA_BUF_SIZE + BUF_EXTRA]; +#if 0 +PRIVATE u8_t buffer[(unsigned) 2 * DMA_BUF_SIZE]; +#endif u8_t *tmp_buf; /* the DMA buffer eventually */ phys_bytes tmp_phys; /* phys address of DMA buffer */ -#else /* CHIP != INTEL */ - -/* Claim space for variables. */ -u8_t tmp_buf[DMA_BUF_SIZE]; /* the DMA buffer */ -phys_bytes tmp_phys; /* phys address of DMA buffer */ - -#endif /* CHIP != INTEL */ - -FORWARD _PROTOTYPE( void init_buffer, (void) ); FORWARD _PROTOTYPE( int do_rdwt, (struct driver *dr, message *mp, int safe) ); FORWARD _PROTOTYPE( int do_vrdwt, (struct driver *dr, message *mp, int safe) ); @@ -86,9 +70,6 @@ struct driver *dp; /* Device dependent entry points. */ /* Init MQ library. */ mq_init(); - /* Get a DMA buffer. */ - init_buffer(); - /* Here is the main loop of the disk task. It waits for a message, carries * it out, and sends a reply. */ @@ -176,25 +157,17 @@ struct driver *dp; /* Device dependent entry points. */ /*===========================================================================* * init_buffer * *===========================================================================*/ -PRIVATE void init_buffer() +PUBLIC void init_buffer(void) { /* Select a buffer that can safely be used for DMA transfers. It may also * be used to read partition tables and such. Its absolute address is * 'tmp_phys', the normal address is 'tmp_buf'. */ -#if (CHIP == INTEL) unsigned left; - tmp_buf = buffer; - sys_umap(SELF, D, (vir_bytes)buffer, (phys_bytes)sizeof(buffer), &tmp_phys); - - if ((left = dma_bytes_left(tmp_phys)) < DMA_BUF_SIZE) { - /* First half of buffer crosses a 64K boundary, can't DMA into that */ - tmp_buf += left; - tmp_phys += left; - } -#endif /* CHIP == INTEL */ + if(!(tmp_buf = alloc_contig(2*DMA_BUF_SIZE, AC_ALIGN4K, &tmp_phys))) + panic(__FILE__, "can't allocate tmp_buf", DMA_BUF_SIZE); } /*===========================================================================* @@ -216,8 +189,8 @@ int safe; /* use safecopies? */ /* Check the user buffer (not relevant for safe copies). */ if(!safe) { - sys_umap(mp->IO_ENDPT, D, (vir_bytes) mp->ADDRESS, mp->COUNT, &phys_addr); - if (phys_addr == 0) return(EFAULT); + printf("libdriver_asyn: do_rdwt: no support for non-safe command.\n"); + return EINVAL; } /* Prepare for I/O. */ diff --git a/drivers/libdriver/driver.h b/drivers/libdriver/driver.h index 8c019e92e..03dd9324b 100644 --- a/drivers/libdriver/driver.h +++ b/drivers/libdriver/driver.h @@ -45,14 +45,6 @@ struct driver { _PROTOTYPE( int (*dr_hw_int), (struct driver *dp, message *m_ptr) ); }; -#if (CHIP == INTEL) - -/* Number of bytes you can DMA before hitting a 64K boundary: */ -#define dma_bytes_left(phys) \ - ((unsigned) (sizeof(int) == 2 ? 0 : 0x10000) - (unsigned) ((phys) & 0xFFFF)) - -#endif /* CHIP == INTEL */ - /* Base and size of a partition in bytes. */ struct device { u64_t dv_base; @@ -75,6 +67,7 @@ _PROTOTYPE( int nop_select, (struct driver *dp, message *m_ptr) ); _PROTOTYPE( int do_diocntl, (struct driver *dp, message *m_ptr, int safe) ); _PROTOTYPE( int nop_ioctl, (struct driver *dp, message *m_ptr, int safe) ); _PROTOTYPE( int mq_queue, (message *m_ptr) ); +_PROTOTYPE( void init_buffer, (void) ); /* Parameters for the disk drive. */ #define SECTOR_SIZE 512 /* physical sector size in bytes */ diff --git a/drivers/libdriver_asyn/Makefile b/drivers/libdriver_asyn/Makefile index 534ac1a69..c88984a15 100644 --- a/drivers/libdriver_asyn/Makefile +++ b/drivers/libdriver_asyn/Makefile @@ -11,7 +11,7 @@ m = $i/minix CC = exec cc CFLAGS = -I$i $(CPROFILE) LDFLAGS = -i -LIBS = -lsysutil -lsys +LIBS = -lsys LIB = libdriver.a OBJECTS = driver.o drvlib.o mq.o diff --git a/drivers/libdriver_asyn/driver.c b/drivers/libdriver_asyn/driver.c index f97173e89..21c137b49 100644 --- a/drivers/libdriver_asyn/driver.c +++ b/drivers/libdriver_asyn/driver.c @@ -43,28 +43,10 @@ #include #include "driver.h" -#if (CHIP == INTEL) - -#if USE_EXTRA_DMA_BUF && DMA_BUF_SIZE < 2048 -/* A bit extra scratch for the Adaptec driver. */ -#define BUF_EXTRA (2048 - DMA_BUF_SIZE) -#else -#define BUF_EXTRA 0 -#endif - /* Claim space for variables. */ -PRIVATE u8_t buffer[(unsigned) 2 * DMA_BUF_SIZE + BUF_EXTRA]; -u8_t *tmp_buf; /* the DMA buffer eventually */ +u8_t *tmp_buf = NULL; /* the DMA buffer eventually */ phys_bytes tmp_phys; /* phys address of DMA buffer */ -#else /* CHIP != INTEL */ - -/* Claim space for variables. */ -u8_t tmp_buf[DMA_BUF_SIZE]; /* the DMA buffer */ -phys_bytes tmp_phys; /* phys address of DMA buffer */ - -#endif /* CHIP != INTEL */ - FORWARD _PROTOTYPE( void init_buffer, (void) ); FORWARD _PROTOTYPE( int do_rdwt, (struct driver *dr, message *mp, int safe) ); FORWARD _PROTOTYPE( int do_vrdwt, (struct driver *dr, message *mp, int safe) ); @@ -88,9 +70,6 @@ struct driver *dp; /* Device dependent entry points. */ /* Init MQ library. */ mq_init(); - /* Get a DMA buffer. */ - init_buffer(); - /* Here is the main loop of the disk task. It waits for a message, carries * it out, and sends a reply. */ @@ -112,6 +91,7 @@ struct driver *dp; /* Device dependent entry points. */ device_caller = mess.m_source; proc_nr = mess.IO_ENDPT; +#if 0 if (mess.m_type != SYN_ALARM && mess.m_type != DEV_PING && mess.m_type != 4105 /* notify from TTY */ && mess.m_type != DEV_SELECT && @@ -119,9 +99,10 @@ struct driver *dp; /* Device dependent entry points. */ mess.m_type != DIAGNOSTICS_S && mess.m_type != CANCEL) { - printf("libdriver_asyn`driver_task: message %d\n", - mess.m_type); + printf("libdriver_asyn`driver_task: msg %d / 0x%x from %d\n", + mess.m_type, mess.m_type, mess.m_source); } +#endif if (mess.m_type == DEV_SELECT) { @@ -129,9 +110,11 @@ struct driver *dp; /* Device dependent entry points. */ if (first) { first= 0; +#if 0 printf( "libdriver_asyn`driver_task: first DEV_SELECT: minor 0x%x, ops 0x%x\n", mess.DEVICE, mess.IO_ENDPT); +#endif } } @@ -223,15 +206,19 @@ struct driver *dp; /* Device dependent entry points. */ } else if (mess.m_type == DIAGNOSTICS_S) { +#if 0 if (device_caller == FS_PROC_NR) printf("driver_task: sending DIAG_REPL to FS\n"); +#endif reply_mess.m_type = DIAG_REPL; reply_mess.REP_STATUS = r; } else { +#if 0 printf("driver_task: TASK_REPLY to req %d\n", mess.m_type); +#endif reply_mess.m_type = TASK_REPLY; reply_mess.REP_ENDPT = proc_nr; /* Status is # of bytes transferred or error code. */ @@ -258,18 +245,11 @@ PRIVATE void init_buffer() * 'tmp_phys', the normal address is 'tmp_buf'. */ -#if (CHIP == INTEL) unsigned left; - tmp_buf = buffer; - sys_umap(SELF, D, (vir_bytes)buffer, (phys_bytes)sizeof(buffer), &tmp_phys); - - if ((left = dma_bytes_left(tmp_phys)) < DMA_BUF_SIZE) { - /* First half of buffer crosses a 64K boundary, can't DMA into that */ - tmp_buf += left; - tmp_phys += left; + if(!(tmp_buf = alloc_contig(2*DMA_BUF_SIZE, 0, &tmp_phys))) { + panic(__FILE__, "can't allocate tmp_buf", NO_NUM); } -#endif /* CHIP == INTEL */ } /*===========================================================================* @@ -557,6 +537,8 @@ PUBLIC int mq_queue(message *m) return OK; } +#if 0 + #define ASYN_NR 100 PRIVATE asynmsg_t msgtable[ASYN_NR]; PRIVATE int first_slot= 0, next_slot= 0; @@ -644,3 +626,4 @@ message *mp; return senda(msgtable+first_slot, next_slot-first_slot); } +#endif diff --git a/drivers/libdriver_asyn/driver.h b/drivers/libdriver_asyn/driver.h index 8c019e92e..0737f1748 100644 --- a/drivers/libdriver_asyn/driver.h +++ b/drivers/libdriver_asyn/driver.h @@ -45,14 +45,6 @@ struct driver { _PROTOTYPE( int (*dr_hw_int), (struct driver *dp, message *m_ptr) ); }; -#if (CHIP == INTEL) - -/* Number of bytes you can DMA before hitting a 64K boundary: */ -#define dma_bytes_left(phys) \ - ((unsigned) (sizeof(int) == 2 ? 0 : 0x10000) - (unsigned) ((phys) & 0xFFFF)) - -#endif /* CHIP == INTEL */ - /* Base and size of a partition in bytes. */ struct device { u64_t dv_base; diff --git a/drivers/log/Makefile b/drivers/log/Makefile index b7f482182..221d1baa1 100644 --- a/drivers/log/Makefile +++ b/drivers/log/Makefile @@ -13,7 +13,7 @@ MAKE = exec make CC = exec cc CFLAGS = -I$i $(CPROFILE) LDFLAGS = -i -L../libdriver_asyn -LIBS = -lsysutil -ldriver -lsys +LIBS = -ldriver -lsys LIB_DEP = ../libdriver_asyn/libdriver.a OBJ = log.o diag.o kputc.o @@ -22,11 +22,11 @@ OBJ = log.o diag.o kputc.o all build: $(DRIVER) $(DRIVER): $(OBJ) $(LIB_DEP) $(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS) - install -S 16kb $(DRIVER) + install -S 32kb $(DRIVER) # install with other drivers install: $(DRIVER) - install -o root -cs $? /sbin/$(DRIVER) + install -o root -cs $< /sbin/$(DRIVER) # clean up local files clean: diff --git a/drivers/log/diag.c b/drivers/log/diag.c index eb8da9e00..0dacbd323 100644 --- a/drivers/log/diag.c +++ b/drivers/log/diag.c @@ -11,11 +11,9 @@ #include #include #include +#include #include "log.h" -#include "../../kernel/const.h" -#include "../../kernel/config.h" -#include "../../kernel/type.h" /*==========================================================================* * do_new_kmess * @@ -24,8 +22,8 @@ PUBLIC int do_new_kmess(m) message *m; /* notification message */ { /* Notification for a new kernel message. */ - struct kmessages kmess; /* entire kmess structure */ - char print_buf[KMESS_BUF_SIZE]; /* copy new message here */ + static struct kmessages kmess; /* entire kmess structure */ + static char print_buf[_KMESS_BUF_SIZE]; /* copy new message here */ int bytes; int i, r; int *prev_nextp; @@ -79,12 +77,12 @@ message *m; /* notification message */ * Check for size being positive, the buffer might as well be emptied! */ if (kmess.km_size > 0) { - bytes = ((kmess.km_next + KMESS_BUF_SIZE) - (*prev_nextp)) % - KMESS_BUF_SIZE; + bytes = ((kmess.km_next + _KMESS_BUF_SIZE) - (*prev_nextp)) % + _KMESS_BUF_SIZE; r= *prev_nextp; /* start at previous old */ i=0; while (bytes > 0) { - print_buf[i] = kmess.km_buf[(r%KMESS_BUF_SIZE)]; + print_buf[i] = kmess.km_buf[(r%_KMESS_BUF_SIZE)]; bytes --; r ++; i ++; @@ -136,5 +134,7 @@ PUBLIC int do_diagnostics(message *m, int safe) } log_append(diagbuf, i); + if(m->m_type == ASYN_DIAGNOSTICS) return EDONTREPLY; + return OK; } diff --git a/drivers/log/log.c b/drivers/log/log.c index 27c58cd16..e22789093 100644 --- a/drivers/log/log.c +++ b/drivers/log/log.c @@ -9,8 +9,6 @@ #include "log.h" #include #include -#include "../../kernel/const.h" -#include "../../kernel/type.h" #define LOG_DEBUG 0 /* enable/ disable debugging */ @@ -403,10 +401,10 @@ int safe; r = do_diagnostics(m_ptr, 0); break; } - case DIAGNOSTICS_S: { + case ASYN_DIAGNOSTICS: + case DIAGNOSTICS_S: r = do_diagnostics(m_ptr, 1); break; - } case DEV_STATUS: { printf("log_other: unexpected DEV_STATUS request\n"); r = EDONTREPLY; diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile index 5b77a1c0d..c3c251237 100644 --- a/drivers/memory/Makefile +++ b/drivers/memory/Makefile @@ -14,7 +14,7 @@ MAKE = exec make CC = exec cc CFLAGS = -I$i LDFLAGS = -i -L../libdriver -LIBS = -lsysutil -ldriver -lsys +LIBS = -ldriver -lsys # imgrd_s.s is the ACK assembler version of the ramdisk. For more portability, # use the C version imgrd.c. However, the C compiler takes too much memory diff --git a/drivers/memory/memory.c b/drivers/memory/memory.c index d5b9af796..520bb9315 100644 --- a/drivers/memory/memory.c +++ b/drivers/memory/memory.c @@ -27,6 +27,7 @@ #define MY_DS_NAME_SIZE "dev:memory:ramdisk_size" #include +#include #include "assert.h" @@ -71,7 +72,7 @@ PRIVATE struct driver m_dtab = { /* One page of temporary mapping area - enough to be able to page-align * one page. */ -static char pagedata_buf[2*PAGE_SIZE]; +static char pagedata_buf[2*I386_PAGE_SIZE]; vir_bytes pagedata_aligned; /* Buffer for the /dev/zero null byte feed. */ @@ -171,8 +172,10 @@ int safe; /* safe copies */ break; /* Virtual copying. For RAM disk, kernel memory and boot device. */ - case RAM_DEV: case KMEM_DEV: + return EIO; + break; + case RAM_DEV: case BOOT_DEV: if (position >= dv_size) return(OK); /* check for EOF */ if (position + count > dv_size) count = dv_size - position; @@ -207,15 +210,19 @@ int safe; /* safe copies */ count = dv_size - position; mem_phys = cv64ul(dv->dv_base) + position; - page_off = mem_phys % PAGE_SIZE; + page_off = mem_phys % I386_PAGE_SIZE; pagestart = mem_phys - page_off; /* All memory to the map call has to be page-aligned. * Don't have to map same page over and over. */ if(!any_mapped || pagestart_mapped != pagestart) { +#if 0 if((r=sys_vm_map(SELF, 1, pagedata_aligned, - PAGE_SIZE, pagestart)) != OK) { + I386_PAGE_SIZE, pagestart)) != OK) { +#else + if(1) { +#endif printf("memory: sys_vm_map failed: %d\n", r); return r; } @@ -224,7 +231,7 @@ int safe; /* safe copies */ } /* how much to be done within this page. */ - subcount = PAGE_SIZE-page_off; + subcount = I386_PAGE_SIZE-page_off; if(subcount > count) subcount = count; @@ -324,12 +331,14 @@ PRIVATE void m_init() } /* Install remote segment for /dev/kmem memory. */ +#if 0 m_geom[KMEM_DEV].dv_base = cvul64(kinfo.kmem_base); m_geom[KMEM_DEV].dv_size = cvul64(kinfo.kmem_size); if (OK != (s=sys_segctl(&m_seg[KMEM_DEV], (u16_t *) &s, (vir_bytes *) &s, kinfo.kmem_base, kinfo.kmem_size))) { panic("MEM","Couldn't install remote segment.",s); } +#endif /* Install remote segment for /dev/boot memory, if enabled. */ m_geom[BOOT_DEV].dv_base = cvul64(kinfo.bootdev_base); @@ -365,8 +374,8 @@ PRIVATE void m_init() } /* Page-align page pointer. */ - pagedata_aligned = (u32_t) pagedata_buf + PAGE_SIZE; - pagedata_aligned -= pagedata_aligned % PAGE_SIZE; + pagedata_aligned = (u32_t) pagedata_buf + I386_PAGE_SIZE; + pagedata_aligned -= pagedata_aligned % I386_PAGE_SIZE; /* Set up memory range for /dev/mem. */ m_geom[MEM_DEV].dv_size = cvul64(0xffffffff); @@ -404,15 +413,11 @@ int safe; if (m_ptr->DEVICE != RAM_DEV) return(EINVAL); if ((dv = m_prepare(m_ptr->DEVICE)) == NIL_DEV) return(ENXIO); -#if 0 - ramdev_size= m_ptr->POSITION; -#else /* Get request structure */ s= sys_safecopyfrom(m_ptr->IO_ENDPT, (vir_bytes)m_ptr->IO_GRANT, 0, (vir_bytes)&ramdev_size, sizeof(ramdev_size), D); if (s != OK) return s; -#endif #if DEBUG printf("allocating ramdisk of size 0x%x\n", ramdev_size); @@ -447,27 +452,6 @@ int safe; first_time= 0; break; } - case MIOCMAP: - case MIOCUNMAP: { - int r, do_map; - struct mapreq mapreq; - - if ((*dp->dr_prepare)(m_ptr->DEVICE) == NIL_DEV) return(ENXIO); - if (m_device != MEM_DEV) - return ENOTTY; - - do_map= (m_ptr->REQUEST == MIOCMAP); /* else unmap */ - - /* Get request structure */ - r= sys_safecopyfrom(m_ptr->IO_ENDPT, (vir_bytes)m_ptr->IO_GRANT, - 0, (vir_bytes)&mapreq, sizeof(mapreq), D); - - if (r != OK) - return r; - r= sys_vm_map(m_ptr->IO_ENDPT, do_map, - (phys_bytes)mapreq.base, mapreq.size, mapreq.offset); - return r; - } default: return(do_diocntl(&m_dtab, m_ptr, safe)); diff --git a/drivers/memory/ramdisk/rc b/drivers/memory/ramdisk/rc index e4e781634..3aae388f8 100644 --- a/drivers/memory/ramdisk/rc +++ b/drivers/memory/ramdisk/rc @@ -9,7 +9,6 @@ then else /bin/service -c up /bin/at_wini -dev /dev/c0d0 -config /etc/drivers.conf -label at_wini_0 /bin/service -c up /bin/at_wini -dev /dev/c1d0 -config /etc/drivers.conf -label at_wini_1 -args ata_instance=1 - #/bin/service -c up /bin/at_wini -dev /dev/c0d0 -script /etc/rs.single -config /etc/drivers.conf fi rootdev=`sysenv rootdev` || echo 'No rootdev?' diff --git a/drivers/orinoco/Makefile b/drivers/orinoco/Makefile index 256fed944..9a1d8900b 100755 --- a/drivers/orinoco/Makefile +++ b/drivers/orinoco/Makefile @@ -13,7 +13,7 @@ d = .. CC = exec cc CFLAGS = -I$i $(CPROFILE) LDFLAGS = -i -LIBS = -lsysutil -lsys -ltimers +LIBS = -lsys -ltimers OBJ = orinoco.o hermes.o diff --git a/drivers/orinoco/hermes.c b/drivers/orinoco/hermes.c index 640edf01a..095553be6 100755 --- a/drivers/orinoco/hermes.c +++ b/drivers/orinoco/hermes.c @@ -44,8 +44,6 @@ #include "string.h" int this_proc; -#define MICROS_TO_TICKS(m) (((m)*HZ/1000000)+1) - /***************************************************************************** * milli_delay * * * diff --git a/drivers/orinoco/orinoco.c b/drivers/orinoco/orinoco.c index c26056d41..2ec3aa71c 100755 --- a/drivers/orinoco/orinoco.c +++ b/drivers/orinoco/orinoco.c @@ -93,7 +93,7 @@ static tmra_ut or_watchdog; #include #include #include -#include +#include #include #include #include @@ -738,24 +738,29 @@ static void map_hw_buffer(t_or *orp) { char *buf, *abuf; hermes_t *hw = &(orp->hw); - /* This way, the buffer will be at least PAGE_SIZE big: see + /* This way, the buffer will be at least I386_PAGE_SIZE big: see * calculation with the offset */ - size = 2 * PAGE_SIZE; + size = 2 * I386_PAGE_SIZE; buf = (char *)malloc(size); if(buf == NULL) panic(__FILE__, "map_hw_buffer: cannot malloc size:", size); - /* Let the mapped memory by PAGE_SIZE aligned */ - o = PAGE_SIZE - ((vir_bytes)buf % PAGE_SIZE); + /* Let the mapped memory by I386_PAGE_SIZE aligned */ + o = I386_PAGE_SIZE - ((vir_bytes)buf % I386_PAGE_SIZE); abuf = buf + o; +#if 0 r = sys_vm_map(SELF, 1, (vir_bytes)abuf, - 1 * PAGE_SIZE, (phys_bytes)orp->or_base_port); + 1 * I386_PAGE_SIZE, (phys_bytes)orp->or_base_port); +#else + r = ENOSYS; +#endif if(r!=OK) panic(__FILE__, "map_hw_buffer: sys_vm_map failed:", r); + hw->locmem = abuf; } diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index a19a1f8f1..60d1fd6f8 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -13,7 +13,7 @@ d = .. CC = cc CFLAGS = -I$i $(CPROFILE) LDFLAGS = -i -LIBS = -lsysutil -lsys -ltimers +LIBS = -lsys -ltimers OBJ = main.o pci.o pci_table.o diff --git a/drivers/pci/main.c b/drivers/pci/main.c index 213fe921c..fba9440fe 100644 --- a/drivers/pci/main.c +++ b/drivers/pci/main.c @@ -388,8 +388,10 @@ message *mp; } acl[i].inuse= 0; +#if 0 printf("do_acl: deleting ACL for %d ('%s') at entry %d\n", acl[i].acl.rsp_endpoint, acl[i].acl.rsp_label, i); +#endif /* Also release all devices held by this process */ pci_release(proc_nr); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 0876c33cc..c319fcda0 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -10,7 +10,7 @@ Created: Jan 2000 by Philip Homburg #include "../drivers.h" #include #include -#include +#include #include #include #include @@ -118,7 +118,9 @@ FORWARD _PROTOTYPE( int do_piix, (int devind) ); FORWARD _PROTOTYPE( int do_amd_isabr, (int devind) ); FORWARD _PROTOTYPE( int do_sis_isabr, (int devind) ); FORWARD _PROTOTYPE( int do_via_isabr, (int devind) ); +#if 0 FORWARD _PROTOTYPE( void report_vga, (int devind) ); +#endif FORWARD _PROTOTYPE( char *pci_vid_name, (U16_t vid) ); FORWARD _PROTOTYPE( char *pci_baseclass_name, (U8_t baseclass) ); FORWARD _PROTOTYPE( char *pci_subclass_name, (U8_t baseclass, @@ -872,8 +874,10 @@ printf("probe_bus(%d)\n", busind); print_capabilities(devind); t3= ((baseclass << 16) | (subclass << 8) | infclass); +#if 0 if (t3 == PCI_T3_VGA || t3 == PCI_T3_VGA_OLD) report_vga(devind); +#endif if (nr_pcidev >= NR_PCIDEV) panic("PCI","too many PCI devices", nr_pcidev); @@ -1406,8 +1410,8 @@ PRIVATE void complete_bars() if (!(pcidev[i].pd_bar[j].pb_flags & PBF_INCOMPLETE)) continue; size= pcidev[i].pd_bar[j].pb_size; - if (size < PAGE_SIZE) - size= PAGE_SIZE; + if (size < I386_PAGE_SIZE) + size= I386_PAGE_SIZE; base= memgap_high-size; base &= ~(u32_t)(size-1); if (base < memgap_low) @@ -2010,6 +2014,7 @@ int devind; } +#if 0 /*===========================================================================* * report_vga * *===========================================================================*/ @@ -2042,6 +2047,7 @@ int devind; amount); } } +#endif /*===========================================================================* diff --git a/drivers/printer/Makefile b/drivers/printer/Makefile index 243bd0dec..7e3228fb4 100644 --- a/drivers/printer/Makefile +++ b/drivers/printer/Makefile @@ -13,7 +13,7 @@ d = .. CC = exec cc CFLAGS = -I$i $(CPROFILE) LDFLAGS = -i -LIBS = -lsysutil -lsys +LIBS = -lsys -lsys OBJ = printer.o diff --git a/drivers/random/Makefile b/drivers/random/Makefile index ec447e5f9..9e376cad5 100644 --- a/drivers/random/Makefile +++ b/drivers/random/Makefile @@ -14,7 +14,7 @@ MAKE = exec make CC = exec cc CFLAGS = -I$i $(CPROFILE) LDFLAGS = -i -L../libdriver_asyn -LIBS = -lsysutil -ldriver -lsys +LIBS = -ldriver -lsys LIB_DEPS=../libdriver_asyn/libdriver.a OBJ = main.o random.o sha2.o aes/rijndael_api.o aes/rijndael_alg.o diff --git a/drivers/readclock/Makefile b/drivers/readclock/Makefile index 2d9a2ebe1..66a32f850 100644 --- a/drivers/readclock/Makefile +++ b/drivers/readclock/Makefile @@ -6,7 +6,7 @@ MAKE = exec make CC = exec cc CFLAGS=-D_MINIX=1 -D_POSIX_SOURCE=1 -D_SYSTEM=1 LDFLAGS = -i -LIBS = -lsysutil -lsys +LIBS = -lsys OBJ = readclock.o diff --git a/drivers/rtl8139/Makefile b/drivers/rtl8139/Makefile index eef744678..0e6d2bb11 100644 --- a/drivers/rtl8139/Makefile +++ b/drivers/rtl8139/Makefile @@ -14,7 +14,7 @@ MAKE = exec make CC = exec cc CFLAGS = -I$i $(CPROFILE) LDFLAGS = -i -LIBS = -lsysutil -lsys -ltimers +LIBS = -lsys -ltimers OBJ = rtl8139.o diff --git a/drivers/sb16/Makefile b/drivers/sb16/Makefile index 4105a446f..3f159633a 100644 --- a/drivers/sb16/Makefile +++ b/drivers/sb16/Makefile @@ -12,7 +12,7 @@ d = .. CC = exec cc CFLAGS = -I$i $(CPROFILE) LDFLAGS = -i -LIBS = -lsysutil -lsys +LIBS = -lsys # build local binary diff --git a/drivers/ti1225/Makefile b/drivers/ti1225/Makefile index dd2512a42..b197db5dd 100644 --- a/drivers/ti1225/Makefile +++ b/drivers/ti1225/Makefile @@ -13,7 +13,7 @@ d = .. CC = exec cc CFLAGS = -I$i $(CPROFILE) LDFLAGS = -i -LIBS = -lsysutil -lsys -ltimers +LIBS = -lsys -ltimers OBJ = ti1225.o diff --git a/drivers/ti1225/ti1225.c b/drivers/ti1225/ti1225.c index f35c3d9ec..eeed9b237 100644 --- a/drivers/ti1225/ti1225.c +++ b/drivers/ti1225/ti1225.c @@ -7,6 +7,7 @@ Created: Dec 2005 by Philip Homburg #include "../drivers.h" #include #include +#include #include "ti1225.h" #include "i82365.h" @@ -29,7 +30,7 @@ PRIVATE struct port char *base_ptr; volatile struct csr *csr_ptr; - char buffer[2*PAGE_SIZE]; + char buffer[2*I386_PAGE_SIZE]; } ports[NR_PORTS]; #define PF_PRESENT 1 @@ -257,8 +258,8 @@ u32_t base; vir_bytes buf_base; buf_base= (vir_bytes)pp->buffer; - if (buf_base % PAGE_SIZE) - buf_base += PAGE_SIZE-(buf_base % PAGE_SIZE); + if (buf_base % I386_PAGE_SIZE) + buf_base += I386_PAGE_SIZE-(buf_base % I386_PAGE_SIZE); pp->base_ptr= (char *)buf_base; if (debug) { @@ -269,8 +270,12 @@ u32_t base; /* Clear low order bits in base */ base &= ~(u32_t)0xF; +#if 0 r= sys_vm_map(SELF, 1 /* map */, (vir_bytes)pp->base_ptr, - PAGE_SIZE, (phys_bytes)base); + I386_PAGE_SIZE, (phys_bytes)base); +#else + r = ENOSYS; +#endif if (r != OK) panic("ti1225", "map_regs: sys_vm_map failed", r); } @@ -422,7 +427,7 @@ struct port *pp; csr_present= pp->csr_ptr->csr_present; if (csr_present & CP_PWRCYCLE) break; - } while (getuptime(&t1)==OK && (t1-t0) < MICROS_TO_TICKS(100000)); + } while (getuptime(&t1)==OK && (t1-t0) < micros_to_ticks(100000)); if (!(csr_present & CP_PWRCYCLE)) { diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile index 4f891d065..710ea9f57 100644 --- a/drivers/tty/Makefile +++ b/drivers/tty/Makefile @@ -14,10 +14,10 @@ d = .. # programs, flags, etc. MAKE = exec make CC = exec cc -CPPFLAGS = -I$i -I../../kernel/arch/$(ARCH)/include +CPPFLAGS = -I$i CFLAGS = $(CPPFLAGS) LDFLAGS = -i -LIBS = -lsysutil -lsys -ltimers +LIBS = -lsys -ltimers OBJ = tty.o console.o vidcopy.o keyboard.o pty.o rs232.o @@ -25,7 +25,7 @@ OBJ = tty.o console.o vidcopy.o keyboard.o pty.o rs232.o all build: $(DRIVER) $(DRIVER): $(OBJ) $(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS) - install -S 8k $(DRIVER) + install -S 16k $(DRIVER) # install with other drivers install: diff --git a/drivers/tty/console.c b/drivers/tty/console.c index c7a2421f5..f7abd263d 100644 --- a/drivers/tty/console.c +++ b/drivers/tty/console.c @@ -20,61 +20,27 @@ #include #include #include +#include +#include #include #include +#include #include "tty.h" -#include "../../kernel/const.h" -#include "../../kernel/config.h" -#include "../../kernel/type.h" - /* Set this to 1 if you want console output duplicated on the first * serial line. */ #define DUP_CONS_TO_SER 0 -/* Definitions used by the console driver. */ -#define MONO_BASE 0xB0000L /* base of mono video memory */ -#define COLOR_BASE 0xB8000L /* base of color video memory */ -#define MONO_SIZE 0x1000 /* 4K mono video memory */ -#define COLOR_SIZE 0x4000 /* 16K color video memory */ -#define EGA_SIZE 0x8000 /* EGA & VGA have at least 32K */ -#define BLANK_COLOR 0x0700 /* determines cursor color on blank screen */ -#define SCROLL_UP 0 /* scroll forward */ -#define SCROLL_DOWN 1 /* scroll backward */ -#define BLANK_MEM ((u16_t *) 0) /* tells mem_vid_copy() to blank the screen */ -#define CONS_RAM_WORDS 80 /* video ram buffer size */ -#define MAX_ESC_PARMS 4 /* number of escape sequence params allowed */ - -/* Constants relating to the controller chips. */ -#define M_6845 0x3B4 /* port for 6845 mono */ -#define C_6845 0x3D4 /* port for 6845 color */ -#define INDEX 0 /* 6845's index register */ -#define DATA 1 /* 6845's data register */ -#define STATUS 6 /* 6845's status register */ -#define VID_ORG 12 /* 6845's origin register */ -#define CURSOR 14 /* 6845's cursor register */ - /* The clock task should provide an interface for this */ #define TIMER_FREQ 1193182L /* clock frequency for timer in PC and AT */ -/* Beeper. */ -#define BEEP_FREQ 0x0533 /* value to put into timer to set beep freq */ -#define B_TIME 3 /* length of CTRL-G beep is ticks */ - -/* definitions used for font management */ -#define GA_SEQUENCER_INDEX 0x3C4 -#define GA_SEQUENCER_DATA 0x3C5 -#define GA_GRAPHICS_INDEX 0x3CE -#define GA_GRAPHICS_DATA 0x3CF -#define GA_VIDEO_ADDRESS 0xA0000L -#define GA_FONT_SIZE 8192 - /* Global variables used by the console driver and assembly support. */ PUBLIC int vid_index; /* index of video segment in remote mem map */ PUBLIC u16_t vid_seg; PUBLIC vir_bytes vid_off; /* video ram is found at vid_seg:vid_off */ -PUBLIC unsigned vid_size; /* 0x2000 for color or 0x0800 for mono */ +PUBLIC phys_bytes vid_size; /* 0x2000 for color or 0x0800 for mono */ +PUBLIC phys_bytes vid_base; PUBLIC unsigned vid_mask; /* 0x1FFF for color or 0x07FF for mono */ PUBLIC unsigned blank_color = BLANK_COLOR; /* display code for blank */ @@ -87,6 +53,7 @@ PRIVATE unsigned font_lines; /* font lines per character */ PRIVATE unsigned scr_width; /* # characters on a line */ PRIVATE unsigned scr_lines; /* # lines on the screen */ PRIVATE unsigned scr_size; /* # characters on the screen */ +PUBLIC unsigned info_location; /* location in video memory of struct */ PRIVATE int disabled_vc = -1; /* Virtual console that was active when * disable_console was called. @@ -95,6 +62,9 @@ PRIVATE int disabled_sm; /* Scroll mode to be restored when re-enabling * console */ +/* boot_tty_info we use to communicate with the boot code. */ +struct boot_tty_info boot_tty_info; + /* Per console data. */ typedef struct console { tty_t *c_tty; /* associated TTY struct */ @@ -113,11 +83,34 @@ typedef struct console { int *c_esc_parmp; /* pointer to current escape parameter */ int c_esc_parmv[MAX_ESC_PARMS]; /* list of escape parameters */ u16_t c_ramqueue[CONS_RAM_WORDS]; /* buffer for video RAM */ + int c_line; /* line no */ } console_t; +#define UPDATEBOOTINFO(ccons, infofield, value) { \ + if(ccons->c_line == 0) { \ + boot_tty_info.infofield = value; \ + mem_vid_copy((u16_t *) &boot_tty_info, \ + info_location/2, sizeof(boot_tty_info)/2); \ + } \ +} + +#define UPDATE_CURSOR(ccons, cursor) { \ + ccons->c_cur = cursor; \ + UPDATEBOOTINFO(ccons, conscursor, ccons->c_cur); \ + if(curcons && ccons == curcons) \ + set_6845(CURSOR, ccons->c_cur); \ +} + +#define UPDATE_ORIGIN(ccons, origin) { \ + ccons->c_org = origin; \ + UPDATEBOOTINFO(ccons, consorigin, ccons->c_org); \ + if (curcons && ccons == curcons) \ + set_6845(VID_ORG, ccons->c_org); \ +} + PRIVATE int nr_cons= 1; /* actual number of consoles */ PRIVATE console_t cons_table[NR_CONS]; -PRIVATE console_t *curcons; /* currently visible */ +PRIVATE console_t *curcons = NULL; /* currently visible */ /* Color if using a color controller. */ #define color (vid_port == C_6845) @@ -142,14 +135,20 @@ FORWARD _PROTOTYPE( void flush, (console_t *cons) ); FORWARD _PROTOTYPE( void parse_escape, (console_t *cons, int c) ); FORWARD _PROTOTYPE( void scroll_screen, (console_t *cons, int dir) ); FORWARD _PROTOTYPE( void set_6845, (int reg, unsigned val) ); -FORWARD _PROTOTYPE( void get_6845, (int reg, unsigned *val) ); FORWARD _PROTOTYPE( void stop_beep, (timer_t *tmrp) ); FORWARD _PROTOTYPE( void cons_org0, (void) ); FORWARD _PROTOTYPE( void disable_console, (void) ); FORWARD _PROTOTYPE( void reenable_console, (void) ); FORWARD _PROTOTYPE( int ga_program, (struct sequence *seq) ); FORWARD _PROTOTYPE( int cons_ioctl, (tty_t *tp, int) ); + +#if DUP_CONS_TO_SER FORWARD _PROTOTYPE( void ser_putc, (char c) ); +#endif + +#if 0 +FORWARD _PROTOTYPE( void get_6845, (int reg, unsigned *val) ); +#endif /*===========================================================================* * cons_write * @@ -174,7 +173,7 @@ int try; /* Check quickly for nothing to do, so this can be called often without * unmodular tests elsewhere. */ - if ((count = tp->tty_outleft) == 0 || tp->tty_inhibited) return; + if ((count = tp->tty_outleft) == 0 || tp->tty_inhibited) return 0; /* Copy the user bytes to buf[] for decent addressing. Loop over the * copies, since the user buffer may be much larger than buf[]. @@ -228,6 +227,8 @@ int try; tp->tty_outcum); tp->tty_outcum = 0; } + + return 0; } /*===========================================================================* @@ -365,9 +366,9 @@ int dir; /* SCROLL_UP or SCROLL_DOWN */ } else if (!wrap && cons->c_org + scr_size + scr_width >= cons->c_limit) { vid_vid_copy(cons->c_org + scr_width, cons->c_start, chars); - cons->c_org = cons->c_start; + UPDATE_ORIGIN(cons, cons->c_start); } else { - cons->c_org = (cons->c_org + scr_width) & vid_mask; + UPDATE_ORIGIN(cons, (cons->c_org + scr_width) & vid_mask); } new_line = (cons->c_org + chars) & vid_mask; } else { @@ -378,9 +379,9 @@ int dir; /* SCROLL_UP or SCROLL_DOWN */ if (!wrap && cons->c_org < cons->c_start + scr_width) { new_org = cons->c_limit - scr_size; vid_vid_copy(cons->c_org, new_org + scr_width, chars); - cons->c_org = new_org; + UPDATE_ORIGIN(cons, new_org); } else { - cons->c_org = (cons->c_org - scr_width) & vid_mask; + UPDATE_ORIGIN(cons, (cons->c_org - scr_width) & vid_mask); } new_line = cons->c_org; } @@ -388,8 +389,6 @@ int dir; /* SCROLL_UP or SCROLL_DOWN */ blank_color = cons->c_blank; mem_vid_copy(BLANK_MEM, new_line, scr_width); - /* Set the new video origin. */ - if (cons == curcons) set_6845(VID_ORG, cons->c_org); flush(cons); } @@ -421,10 +420,8 @@ register console_t *cons; /* pointer to console struct */ if (cons->c_row < 0) cons->c_row = 0; if (cons->c_row >= scr_lines) cons->c_row = scr_lines - 1; cur = cons->c_org + cons->c_row * scr_width + cons->c_column; - if (cur != cons->c_cur) { - if (cons == curcons) set_6845(CURSOR, cur); - cons->c_cur = cur; - } + if (cur != cons->c_cur) + UPDATE_CURSOR(cons, cur); } /*===========================================================================* @@ -747,6 +744,7 @@ unsigned val; /* 16-bit value to set it to */ sys_voutb(char_out, 4); /* do actual output */ } +#if 0 /*===========================================================================* * get_6845 * *===========================================================================*/ @@ -765,6 +763,7 @@ unsigned *val; /* 16-bit value to set it to */ v2 = v; *val = (v1 << 8) | v2; } +#endif /*===========================================================================* * beep * @@ -810,8 +809,7 @@ PRIVATE void beep() *===========================================================================*/ PUBLIC void do_video(message *m) { - int i, n, r, ops, watch, safe = 0; - unsigned char c; + int r, safe = 0; /* Execute the requested device driver function. */ r= EINVAL; /* just in case */ @@ -827,8 +825,10 @@ PUBLIC void do_video(message *m) break; case DEV_IOCTL_S: safe=1; - if (m->TTY_REQUEST == MIOCMAP || m->TTY_REQUEST == MIOCUNMAP) - { + switch(m->TTY_REQUEST) { + case MIOCMAP: + case MIOCUNMAP: { +#if 0 int r, do_map; struct mapreq mapreq; @@ -859,8 +859,50 @@ PUBLIC void do_video(message *m) r= sys_vm_map(safe ? m->POSITION : m->IO_ENDPT, do_map, (phys_bytes)mapreq.base, mapreq.size, mapreq.offset); +#else + r = ENOSYS; + printf("tty: %ld used old MIOCMAP interface\n", + safe ? m->POSITION : m->IO_ENDPT); +#endif tty_reply(TASK_REPLY, m->m_source, m->IO_ENDPT, r); return; + } + case TIOCMAPMEM: + case TIOCUNMAPMEM: { + int r, do_map; + struct mapreqvm mapreqvm; + void *result; + + do_map= (m->REQUEST == TIOCMAPMEM); /* else unmap */ + + /* Get request structure */ + if(safe) { + r = sys_safecopyfrom(m->IO_ENDPT, + (vir_bytes)m->ADDRESS, 0, (vir_bytes) &mapreqvm, + sizeof(mapreqvm), D); + } else { + r= sys_vircopy(m->IO_ENDPT, D, + (vir_bytes)m->ADDRESS, + SELF, D, (vir_bytes)&mapreqvm,sizeof(mapreqvm)); + } + if (r != OK) + { + tty_reply(TASK_REPLY, m->m_source, m->IO_ENDPT, + r); + return; + } + + /* In safe ioctl mode, the POSITION field contains + * the endpt number of the original requestor. + * IO_ENDPT is always FS. + */ + + if(do_map) { + } else { + } + tty_reply(TASK_REPLY, m->m_source, m->IO_ENDPT, r); + return; + } } r= ENOTTY; break; @@ -940,19 +982,19 @@ tty_t *tp; { /* Initialize the screen driver. */ console_t *cons; - phys_bytes vid_base; u16_t bios_columns, bios_crtbase, bios_fontlines; u8_t bios_rows; int line; int s; static int vdu_initialized = 0; - unsigned page_size; + static unsigned page_size; /* Associate console and TTY. */ line = tp - &tty_table[0]; if (line >= nr_cons) return; cons = &cons_table[line]; cons->c_tty = tp; + cons->c_line = line; tp->tty_priv = cons; /* Fill in TTY function hooks. */ @@ -987,6 +1029,7 @@ tty_t *tp; } if (machine.vdu_ega) vid_size = EGA_SIZE; wrap = ! machine.vdu_ega; + info_location = vid_size - sizeof(struct boot_tty_info); s = sys_segctl(&vid_index, &vid_seg, &vid_off, vid_base, vid_size); @@ -997,7 +1040,8 @@ tty_t *tp; scr_size = scr_lines * scr_width; /* There can be as many consoles as video memory allows. */ - nr_cons = vid_size / scr_size; + nr_cons = (vid_size - sizeof(struct boot_tty_info)/2) / scr_size; + if (nr_cons > NR_CONS) nr_cons = NR_CONS; if (nr_cons > 1) wrap = 0; page_size = vid_size / nr_cons; @@ -1013,13 +1057,18 @@ tty_t *tp; blank_color = BLANK_COLOR; mem_vid_copy(BLANK_MEM, cons->c_start, scr_size); } else { - int i, n; /* Set the cursor of the console vty at the bottom. c_cur * is updated automatically later. */ scroll_screen(cons, SCROLL_UP); cons->c_row = scr_lines - 1; cons->c_column = 0; + + memset(&boot_tty_info, 0, sizeof(boot_tty_info)); + UPDATE_CURSOR(cons, cons->c_cur); + UPDATE_ORIGIN(cons, cons->c_org); + boot_tty_info.flags = BTIF_CONSCURSOR | BTIF_CONSORIGIN; + boot_tty_info.magic = TTYMAGIC; } select_console(0); cons_ioctl(tp, 0); @@ -1045,9 +1094,9 @@ int c; cons_putk(c); if (c != 0) { kmess.km_buf[kmess.km_next] = c; /* put normal char in buffer */ - if (kmess.km_size < KMESS_BUF_SIZE) + if (kmess.km_size < _KMESS_BUF_SIZE) kmess.km_size += 1; - kmess.km_next = (kmess.km_next + 1) % KMESS_BUF_SIZE; + kmess.km_next = (kmess.km_next + 1) % _KMESS_BUF_SIZE; } else { notify(LOG_PROC_NR); } @@ -1060,9 +1109,8 @@ PUBLIC void do_new_kmess(m) message *m; { /* Notification for a new kernel message. */ - struct kmessages kmess; /* kmessages structure */ + static struct kmessages kmess; /* kmessages structure */ static int prev_next = 0; /* previous next seen */ - int size, next; int bytes; int r; @@ -1081,15 +1129,15 @@ message *m; /* Print only the new part. Determine how many new bytes there are with * help of the current and previous 'next' index. Note that the kernel - * buffer is circular. This works fine if less then KMESS_BUF_SIZE bytes - * is new data; else we miss % KMESS_BUF_SIZE here. + * buffer is circular. This works fine if less then _KMESS_BUF_SIZE bytes + * is new data; else we miss % _KMESS_BUF_SIZE here. * Check for size being positive, the buffer might as well be emptied! */ if (kmess.km_size > 0) { - bytes = ((kmess.km_next + KMESS_BUF_SIZE) - prev_next) % KMESS_BUF_SIZE; + bytes = ((kmess.km_next + _KMESS_BUF_SIZE) - prev_next) % _KMESS_BUF_SIZE; r=prev_next; /* start at previous old */ while (bytes > 0) { - cons_putk( kmess.km_buf[(r%KMESS_BUF_SIZE)] ); + cons_putk( kmess.km_buf[(r%_KMESS_BUF_SIZE)] ); bytes --; r ++; } @@ -1121,6 +1169,8 @@ int safe; int r; if(safe) { r = sys_safecopyfrom(proc_nr, src, offset, (vir_bytes) &c, 1, D); + if(r != OK) + printf("", proc_nr, src); } else { r = sys_vircopy(proc_nr, D, src+offset, SELF, D, (vir_bytes) &c, 1); } @@ -1132,9 +1182,12 @@ int safe; cons_putk(c); } cons_putk(0); /* always terminate, even with EFAULT */ - m_ptr->m_type = DIAG_REPL; - m_ptr->REP_STATUS = result; - send(m_ptr->m_source, m_ptr); + + if(m_ptr->m_type != ASYN_DIAGNOSTICS) { + m_ptr->m_type = DIAG_REPL; + m_ptr->REP_STATUS = result; + send(m_ptr->m_source, m_ptr); + } } /*===========================================================================* @@ -1237,7 +1290,7 @@ PRIVATE void cons_org0() if (n > cons->c_org - cons->c_start) n = cons->c_org - cons->c_start; vid_vid_copy(cons->c_org, cons->c_org - n, scr_size); - cons->c_org -= n; + UPDATE_ORIGIN(cons, cons->c_org - n); } flush(cons); } @@ -1283,10 +1336,12 @@ PUBLIC void select_console(int cons_line) /* Set the current console to console number 'cons_line'. */ if (cons_line < 0 || cons_line >= nr_cons) return; + ccurrent = cons_line; curcons = &cons_table[cons_line]; - set_6845(VID_ORG, curcons->c_org); - set_6845(CURSOR, curcons->c_cur); + + UPDATE_CURSOR(curcons, curcons->c_cur); + UPDATE_ORIGIN(curcons, curcons->c_org); } /*===========================================================================* @@ -1358,8 +1413,11 @@ int try; tp->tty_winsize.ws_col= scr_width; tp->tty_winsize.ws_xpixel= scr_width * 8; tp->tty_winsize.ws_ypixel= scr_lines * font_lines; + + return 0; } +#if DUP_CONS_TO_SER #define COM1_BASE 0x3F8 #define COM1_THR (COM1_BASE + 0) #define LSR_THRE 0x20 @@ -1381,3 +1439,4 @@ PRIVATE void ser_putc(char c) } sys_outb(thr, c); } +#endif diff --git a/drivers/tty/keyboard.c b/drivers/tty/keyboard.c index 3325cd951..5ff44c89b 100644 --- a/drivers/tty/keyboard.c +++ b/drivers/tty/keyboard.c @@ -14,16 +14,11 @@ #include #include #include -#include #include #include #include #include "tty.h" #include "keymaps/us-std.src" -#include "../../kernel/const.h" -#include "../../kernel/config.h" -#include "../../kernel/type.h" -#include "../../kernel/proc.h" int irq_hook_id = -1; int aux_irq_hook_id = -1; @@ -132,10 +127,9 @@ PRIVATE struct kbd_outack PRIVATE int kbd_watchdog_set= 0; PRIVATE int kbd_alive= 1; +PRIVATE int sticky_alt_mode = 0; PRIVATE timer_t tmr_kbd_wd; -int sticky_alt_mode = 0; - FORWARD _PROTOTYPE( void handle_req, (struct kbd *kbdp, message *m) ); FORWARD _PROTOTYPE( int handle_status, (struct kbd *kbdp, message *m) ); FORWARD _PROTOTYPE( void kbc_cmd0, (int cmd) ); @@ -153,6 +147,13 @@ FORWARD _PROTOTYPE( int kb_read, (struct tty *tp, int try) ); FORWARD _PROTOTYPE( unsigned map_key, (int scode) ); FORWARD _PROTOTYPE( void kbd_watchdog, (timer_t *tmrp) ); +int micro_delay(u32_t usecs) +{ + /* TTY can't use the library micro_delay() as that calls PM. */ + tickdelay(micros_to_ticks(usecs)); + return OK; +} + /*===========================================================================* * do_kbd * *===========================================================================*/ @@ -500,7 +501,6 @@ message *m_ptr; int o, isaux; unsigned char scode; struct kbd *kbdp; - static timer_t timer; /* timer must be static! */ /* Fetch the character from the keyboard hardware and acknowledge it. */ if (!scan_keyboard(&scode, &isaux)) @@ -637,7 +637,7 @@ PRIVATE void kbd_send() } if (sb & (KB_OUT_FULL|KB_IN_FULL)) { - printf("not sending 1: sb = 0x%x\n", sb); + printf("not sending 1: sb = 0x%lx\n", sb); return; } micro_delay(KBC_IN_DELAY); @@ -646,7 +646,7 @@ PRIVATE void kbd_send() } if (sb & (KB_OUT_FULL|KB_IN_FULL)) { - printf("not sending 2: sb = 0x%x\n", sb); + printf("not sending 2: sb = 0x%lx\n", sb); return; } @@ -864,10 +864,10 @@ PRIVATE int kbc_read() while (micro_elapsed(&ms) < 1000000); #endif panic("TTY", "kbc_read failed to complete", NO_NUM); + return EINVAL; } - /*===========================================================================* * kb_wait * *===========================================================================*/ @@ -876,7 +876,7 @@ PRIVATE int kb_wait() /* Wait until the controller is ready; return zero if this times out. */ int retries; - unsigned long status, temp; + unsigned long status; int s, isaux; unsigned char byte; @@ -940,6 +940,12 @@ PUBLIC void kb_init_once(void) { int i; u8_t ccb; + char env[100]; + + if(env_get_param("sticky_alt", env, sizeof(env)-1) == OK + && atoi(env) == 1) { + sticky_alt_mode = 1; + } set_leds(); /* turn off numlock led */ scan_keyboard(NULL, NULL); /* discard leftover keystroke */ @@ -1020,7 +1026,7 @@ message *m_ptr; /* pointer to the request message */ * notifications if it is pressed. At most one binding per key can exist. */ int i; - int result; + int result = EINVAL; switch (m_ptr->FKEY_REQUEST) { /* see what we must do */ case FKEY_MAP: /* request for new mapping */ @@ -1104,8 +1110,6 @@ message *m_ptr; /* pointer to the request message */ } } break; - default: - result = EINVAL; /* key cannot be observed */ } /* Almost done, return result to caller. */ @@ -1128,7 +1132,6 @@ int scode; /* scan code for a function key */ message m; int key; int proc_nr; - int i,s; /* Ignore key releases. If this is a key press, get full key code. */ if (scode & KEY_RELEASE) return(FALSE); /* key release */ @@ -1166,31 +1169,17 @@ int scode; /* scan code for a function key */ *===========================================================================*/ PRIVATE void show_key_mappings() { - int i,s; - struct proc proc; - + int i; printf("\n"); printf("System information. Known function key mappings to request debug dumps:\n"); printf("-------------------------------------------------------------------------\n"); for (i=0; i<12; i++) { printf(" %sF%d: ", i+1<10? " ":"", i+1); - if (fkey_obs[i].proc_nr != NONE) { - if ((s=sys_getproc(&proc, fkey_obs[i].proc_nr))!=OK) - printf("sys_getproc: %d\n", s); - printf("%-14.14s", proc.p_name); - } else { - printf("%-14.14s", ""); - } + printf("%-14.14s", ""); printf(" %sShift-F%d: ", i+1<10? " ":"", i+1); - if (sfkey_obs[i].proc_nr != NONE) { - if ((s=sys_getproc(&proc, sfkey_obs[i].proc_nr))!=OK) - printf("sys_getproc: %d\n", s); - printf("%-14.14s", proc.p_name); - } else { - printf("%-14.14s", ""); - } + printf("%-14.14s", ""); printf("\n"); } printf("\n"); @@ -1260,12 +1249,6 @@ int *isauxp; #endif } -int micro_delay(u32_t usecs) -{ - tickdelay(MICROS_TO_TICKS(usecs)); - return OK; -} - /*===========================================================================* * kbd_watchdog * *===========================================================================*/ diff --git a/drivers/tty/keymaps/Makefile b/drivers/tty/keymaps/Makefile index 24943e99f..952a806d5 100644 --- a/drivers/tty/keymaps/Makefile +++ b/drivers/tty/keymaps/Makefile @@ -4,8 +4,8 @@ LK = /usr/lib/keymaps .SUFFIXES: .src .map -.src.map: - $(CC) -DKEYSRC=\"$<\" $(CPROFILE) genmap.c -lsysutil -lsys +.src.map: + $(CC) -DKEYSRC=\"$<\" genmap.c ./a.out > $@ @rm -f a.out diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index b90fe6e80..ca408d691 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -89,7 +89,6 @@ message *m_ptr; /* Perform an open/close/read/write call on a /dev/ptypX device. */ pty_t *pp = tp->tty_priv; int r; - phys_bytes p; int safe = 0; switch (m_ptr->m_type) { @@ -108,15 +107,6 @@ message *m_ptr; r = EINVAL; break; } -#if DEAD_CODE - if (numap_local(m_ptr->IO_ENDPT, (vir_bytes) m_ptr->ADDRESS, - m_ptr->COUNT) == 0) { -#else - if ((r = sys_umap(m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS, - m_ptr->COUNT, &p)) != OK) { -#endif - break; - } pp->rdsendreply = TRUE; pp->rdcaller = m_ptr->m_source; pp->rdproc = m_ptr->IO_ENDPT; @@ -130,12 +120,6 @@ message *m_ptr; return; /* already done */ } -#if DEAD_CODE - if (m_ptr->TTY_FLAGS & O_NONBLOCK) { - r = EAGAIN; /* don't suspend */ - pp->rdleft = pp->rdcum = 0; - } else -#endif { r = SUSPEND; /* do suspend */ pp->rdsendreply = FALSE; @@ -157,16 +141,6 @@ message *m_ptr; r = EINVAL; break; } -#if DEAD_CODE - if (numap_local(m_ptr->IO_ENDPT, (vir_bytes) m_ptr->ADDRESS, - m_ptr->COUNT) == 0) { - r = EFAULT; -#else - if ((r = sys_umap(m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS, - m_ptr->COUNT, &p)) != OK) { -#endif - break; - } pp->wrsendreply = TRUE; pp->wrcaller = m_ptr->m_source; pp->wrproc = m_ptr->IO_ENDPT; @@ -179,12 +153,6 @@ message *m_ptr; return; /* already done */ } -#if DEAD_CODE - if (m_ptr->TTY_FLAGS & O_NONBLOCK) { /* don't suspend */ - r = pp->wrcum > 0 ? pp->wrcum : EAGAIN; - pp->wrleft = pp->wrcum = 0; - } else -#endif { pp->wrsendreply = FALSE; /* do suspend */ r = SUSPEND; @@ -244,7 +212,7 @@ int try; */ pty_t *pp = tp->tty_priv; int count, ocount, s; - phys_bytes user_phys; + /* PTY closed down? */ if (pp->state & PTY_CLOSED) { @@ -259,7 +227,7 @@ int try; tp->tty_outleft = tp->tty_outcum = 0; } } - return; + return 0; } /* While there is something to do. */ @@ -473,6 +441,8 @@ int try; notify(pp->wrcaller); } } + + return 0; } /*===========================================================================* @@ -485,7 +455,7 @@ int try; /* The tty side has closed, so shut down the pty side. */ pty_t *pp = tp->tty_priv; - if (!(pp->state & PTY_ACTIVE)) return; + if (!(pp->state & PTY_ACTIVE)) return 0; if (pp->rdleft > 0) { assert(!pp->rdsendreply); @@ -498,6 +468,8 @@ int try; } if (pp->state & PTY_CLOSED) pp->state = 0; else pp->state |= TTY_CLOSED; + + return 0; } /*===========================================================================* @@ -515,6 +487,8 @@ int try; pp->wrleft= 0; notify(pp->wrcaller); } + + return 0; } /*===========================================================================* @@ -529,6 +503,8 @@ int try; pp->ocount = 0; pp->otail = pp->ohead; + + return 0; } /*===========================================================================* diff --git a/drivers/tty/rs232.c b/drivers/tty/rs232.c index a0afd5450..8bc70599f 100644 --- a/drivers/tty/rs232.c +++ b/drivers/tty/rs232.c @@ -11,21 +11,6 @@ #if NR_RS_LINES > 0 -#if (MACHINE != IBM_PC) && (MACHINE != ATARI) -#error /* rs232.c only supports PC and Atari ST */ -#endif - -#if (MACHINE == ATARI) -#include "staddr.h" -#include "stsound.h" -#include "stmfp.h" -#if (NR_RS_LINES > 1) -#error /* Only one physical RS232 line available */ -#endif -#endif - -#if (MACHINE == IBM_PC) /* PC/AT 8250/16450 chip combination */ - /* 8250 constants. */ #define UART_FREQ 115200L /* timer frequency */ @@ -65,46 +50,25 @@ #define MS_RLSD 0x80 /* Received Line Signal Detect */ #define MS_DRLSD 0x08 /* RLSD Delta */ -#else /* MACHINE == ATARI */ /* Atari ST 68901 USART */ +#define DATA_BITS_SHIFT 8 /* amount data bits shifted in mode */ +#define DEF_BAUD 1200 /* default baud rate */ -/* Most of the USART constants are already defined in stmfp.h . The local - * definitions made here are for keeping C code changes smaller. --kub - */ - -#define UART_FREQ 19200L /* timer frequency */ - -/* Line status bits. */ -#define LS_OVERRUN_ERR R_OE -#define LS_PARITY_ERR R_PE -#define LS_FRAMING_ERR R_FE -#define LS_BREAK_INTERRUPT R_BREAK - -/* Modem status bits. */ -#define MS_CTS IO_SCTS /* 0x04 */ - -#endif /* MACHINE == ATARI */ - -#define DATA_BITS_SHIFT 8 /* amount data bits shifted in mode */ -#define DEF_BAUD 1200 /* default baud rate */ - -#define RS_IBUFSIZE 1024 /* RS232 input buffer size */ -#define RS_OBUFSIZE 1024 /* RS232 output buffer size */ +#define RS_IBUFSIZE 1024 /* RS232 input buffer size */ +#define RS_OBUFSIZE 1024 /* RS232 output buffer size */ /* Input buffer watermarks. * The external device is asked to stop sending when the buffer * exactly reaches high water, or when TTY requests it. Sending restarts * when the input buffer empties below the low watermark. */ -#define RS_ILOWWATER (1 * RS_IBUFSIZE / 4) -#define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4) +#define RS_ILOWWATER (1 * RS_IBUFSIZE / 4) +#define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4) /* Output buffer low watermark. * TTY is notified when the output buffer empties below the low watermark, so * it may continue filling the buffer if doing a large write. */ -#define RS_OLOWWATER (1 * RS_OBUFSIZE / 4) - -#if (MACHINE == IBM_PC) +#define RS_OLOWWATER (1 * RS_OBUFSIZE / 4) /* Macros to handle flow control. * Interrupts must be off when they are used. @@ -141,36 +105,6 @@ #define devhup(rs) \ ((my_inb(rs->modem_status_port) & (MS_RLSD|MS_DRLSD)) == MS_DRLSD) -#else /* MACHINE == ATARI */ - -/* Macros to handle flow control. - * Time is critical - already the function call for lock()/restore() is - * annoying. - * istart() tells external device we are ready by raising RTS. - * istop() tells external device we are not ready by dropping RTS. - * DTR is kept high all the time (it probably should be raised by open and - * dropped by close of the device). NOTE: The modem lines are active low. - */ -#define set_porta(msk,val) { register int s = lock(); \ - SOUND->sd_selr = YM_IOA; \ - SOUND->sd_wdat = \ - SOUND->sd_rdat & (msk) | (val); \ - restore(s); } -#define istart(rs) { set_porta( ~(PA_SRTS|PA_SDTR),0 ); \ - (rs)->idevready = TRUE; } -#define istop(rs) { set_porta( ~PA_SDTR, PA_SRTS ); \ - (rs)->idevready = FALSE; } - -/* Macro to tell if device is ready. The rs->cts field is set to MS_CTS if - * CLOCAL is in effect for a line without a CTS wire. - */ -#define devready(rs) ((~MFP->mf_gpip | rs->cts) & MS_CTS) - -/* Transmitter ready test */ -#define txready(rs) (MFP->mf_tsr & (T_EMPTY | T_UE)) - -#endif /* MACHINE == ATARI */ - /* Types. */ typedef unsigned char bool_t; /* boolean */ @@ -234,11 +168,6 @@ typedef struct rs232 { PUBLIC rs232_t rs_lines[NR_RS_LINES]; -/* Table and macro to translate an RS232 line number to its rs_lines entry. */ -PRIVATE rs232_t *p_rs_addr[NR_RS_LINES]; - -#define rs_addr(line) (p_rs_addr[line]) - #if (MACHINE == IBM_PC) /* 8250 base addresses. */ PRIVATE port_t addr_8250[] = { @@ -472,7 +401,6 @@ rs232_t *rs; /* which line */ } if (divisor == 0) return; /* B0? */ -#if (MACHINE == IBM_PC) /* Compute line control flag bits. */ line_controls = 0; if (tp->tty_termios.c_cflag & PARENB) { @@ -502,27 +430,6 @@ rs232_t *rs; /* which line */ rs->ostate &= ~ORAW; unlock(); - -#else /* MACHINE == ATARI */ - - line_controls = U_Q16; - if (tp->tty_termios.c_cflag & PARENB) { - line_controls |= U_PAR; - if (!(tp->tty_termios.c_cflag & PARODD)) line_controls |= U_EVEN; - } - line_controls |= (divisor >= (UART_FREQ / 110)) ? U_ST2 : U_ST1; - - switch (tp->tty_termios.c_cflag & CSIZE) { /* XXX - are U_Dn like CSn? */ - case CS5: line_controls |= U_D5; break; - case CS5: line_controls |= U_D6; break; - case CS5: line_controls |= U_D7; break; - case CS5: line_controls |= U_D8; break; - } - lock(); - MFP->mf_ucr = line_controls; - MFP->mf_tddr = divisor; - unlock(); -#endif /* MACHINE == ATARI */ } /*===========================================================================* @@ -536,11 +443,8 @@ tty_t *tp; /* which TTY */ register rs232_t *rs; int line; -#if (MACHINE == IBM_PC) port_t this_8250; int irq; - long v; -#endif /* Associate RS232 and TTY structures. */ line = tp - &tty_table[NR_CONS]; @@ -550,7 +454,6 @@ tty_t *tp; /* which TTY */ /* Set up input queue. */ rs->ihead = rs->itail = rs->ibuf; -#if (MACHINE == IBM_PC) /* Precalculate port numbers for speed. Magic numbers in the code (once). */ this_8250 = addr_8250[line]; rs->xmit_port = this_8250 + 0; @@ -563,7 +466,6 @@ tty_t *tp; /* which TTY */ rs->modem_ctl_port = this_8250 + 4; rs->line_status_port = this_8250 + 5; rs->modem_status_port = this_8250 + 6; -#endif /* Set up the hardware to a base state, in particular * o turn off DTR (MC_DTR) to try to stop the external device. @@ -580,22 +482,17 @@ tty_t *tp; /* which TTY */ */ istop(rs); /* sets modem_ctl_port */ rs_config(rs); -#if (MACHINE == IBM_PC) sys_outb(rs->int_enab_port, 0); -#endif /* Clear any harmful leftover interrupts. An output interrupt is harmless * and will occur when interrupts are enabled anyway. Set up the output * queue using the status from clearing the modem status interrupt. */ -#if (MACHINE == IBM_PC) sys_inb(rs->line_status_port, &dummy); sys_inb(rs->recv_port, &dummy); -#endif rs->ostate = devready(rs) | ORAW | OSWREADY; /* reads modem_ctl_port */ rs->ohead = rs->otail = rs->obuf; -#if (MACHINE == IBM_PC) /* Enable interrupts for both interrupt controller and device. */ irq = (line & 1) == 0 ? RS232_IRQ : SECONDARY_IRQ; @@ -613,20 +510,6 @@ tty_t *tp; /* which TTY */ sys_outb(rs->int_enab_port, IE_LINE_STATUS_CHANGE | IE_MODEM_STATUS_CHANGE | IE_RECEIVER_READY | IE_TRANSMITTER_READY); -#else /* MACHINE == ATARI */ - /* Initialize the 68901 chip, then enable interrupts. */ - MFP->mf_scr = 0x00; - MFP->mf_tcdcr |= T_Q004; - MFP->mf_rsr = R_ENA; - MFP->mf_tsr = T_ENA; - MFP->mf_aer = (MFP->mf_aer | (IO_SCTS|IO_SDCD)) ^ - (MFP->mf_gpip & (IO_SCTS|IO_SDCD)); - MFP->mf_ddr = (MFP->mf_ddr & ~ (IO_SCTS|IO_SDCD)); - MFP->mf_iera |= (IA_RRDY|IA_RERR|IA_TRDY|IA_TERR); - MFP->mf_imra |= (IA_RRDY|IA_RERR|IA_TRDY|IA_TERR); - MFP->mf_ierb |= (IB_SCTS|IB_SDCD); - MFP->mf_imrb |= (IB_SCTS|IB_SDCD); -#endif /* MACHINE == ATARI */ /* Fill in TTY function hooks. */ tp->tty_devread = rs_read; @@ -721,7 +604,7 @@ int try; if (ostate & ODEVHUP) { sigchar(tp, SIGHUP); tp->tty_termios.c_ospeed = B0; /* Disable further I/O. */ - return; + return 0; } } @@ -744,6 +627,8 @@ int try; unlock(); if ((rs->itail += count) == bufend(rs->ibuf)) rs->itail = rs->ibuf; } + + return 0; } /*===========================================================================* @@ -787,7 +672,6 @@ int dummy; { /* The line is closed; optionally hang up. */ rs232_t *rs = tp->tty_priv; - int r; if (tp->tty_termios.c_cflag & HUPCL) { sys_outb(rs->modem_ctl_port, MC_OUT2 | MC_RTS); @@ -797,7 +681,6 @@ int dummy; /* Low level (interrupt) routines. */ -#if (MACHINE == IBM_PC) /*===========================================================================* * rs232_handler * *===========================================================================*/ @@ -831,50 +714,6 @@ struct rs232 *rs; return; } } -#endif /* MACHINE == IBM_PC */ - -#if (MACHINE == ATARI) -/*===========================================================================* - * siaint * - *===========================================================================*/ -PRIVATE void siaint(type) -int type; /* interrupt type */ -{ -/* siaint is the rs232 interrupt procedure for Atari ST's. For ST there are - * as much as 5 interrupt lines used for rs232. The trap type byte left on the - * stack by the assembler interrupt handler identifies the interrupt cause. - */ - - register unsigned char code; - register rs232_t *rs = &rs_lines[0]; - int s = lock(); - - switch (type & 0x00FF) - { - case 0x00: /* receive buffer full */ - in_int(rs); - break; - case 0x01: /* receive error */ - line_int(rs); - break; - case 0x02: /* transmit buffer empty */ - out_int(rs); - break; - case 0x03: /* transmit error */ - code = MFP->mf_tsr; - if (code & ~(T_ENA | T_UE | T_EMPTY)) - { - printf("sia: transmit error: status=%x\r\n", code); - /* MFP->mf_udr = lastchar; */ /* retry */ - } - break; - case 0x04: /* modem lines change */ - modem_int(rs); - break; - } - restore(s); -} -#endif /* MACHINE == ATARI */ /*===========================================================================* * in_int * @@ -895,11 +734,7 @@ register rs232_t *rs; /* line with input interrupt */ return; #endif -#if (MACHINE == IBM_PC) sys_inb(rs->recv_port, &c); -#else /* MACHINE == ATARI */ - c = MFP->mf_udr; -#endif if (!(rs->ostate & ORAW)) { if (c == rs->oxoff) { @@ -937,14 +772,8 @@ register rs232_t *rs; /* line with line status interrupt */ /* Check for and record errors. */ unsigned long s; -#if (MACHINE == IBM_PC) sys_inb(rs->line_status_port, &s); rs->lstatus = s; -#else /* MACHINE == ATARI */ - rs->lstatus = MFP->mf_rsr; - MFP->mf_rsr &= R_ENA; - rs->pad = MFP->mf_udr; /* discard char in case of LS_OVERRUN_ERR */ -#endif /* MACHINE == ATARI */ if (rs->lstatus & LS_FRAMING_ERR) ++rs->framing_errors; if (rs->lstatus & LS_OVERRUN_ERR) ++rs->overrun_errors; if (rs->lstatus & LS_PARITY_ERR) ++rs->parity_errors; @@ -961,12 +790,6 @@ register rs232_t *rs; /* line with modem interrupt */ * If the device just became ready, restart output. */ -#if (MACHINE == ATARI) - /* Set active edge interrupt so that next change causes a new interrupt */ - MFP->mf_aer = (MFP->mf_aer | (IO_SCTS|IO_SDCD)) ^ - (MFP->mf_gpip & (IO_SCTS|IO_SDCD)); -#endif - if (devhup(rs)) { rs->ostate |= ODEVHUP; rs->tty->tty_events = 1; @@ -994,11 +817,7 @@ register rs232_t *rs; /* line with output interrupt */ if (rs->ostate >= (ODEVREADY | OQUEUED | OSWREADY)) { /* Bit test allows ORAW and requires the others. */ -#if (MACHINE == IBM_PC) sys_outb(rs->xmit_port, *rs->otail); -#else /* MACHINE == ATARI */ - MFP->mf_udr = *rs->otail; -#endif if (++rs->otail == bufend(rs->obuf)) rs->otail = rs->obuf; if (--rs->ocount == 0) { rs->ostate ^= (ODONE | OQUEUED); /* ODONE on, OQUEUED off */ diff --git a/drivers/tty/tty.c b/drivers/tty/tty.c index 56b412477..15dac4ee1 100644 --- a/drivers/tty/tty.c +++ b/drivers/tty/tty.c @@ -61,9 +61,9 @@ #include #include #include -#if (CHIP == INTEL) +#include +#include #include -#endif #include "tty.h" #include @@ -92,6 +92,7 @@ unsigned long rs_irq_set = 0; #if NR_RS_LINES == 0 #define rs_init(tp) ((void) 0) #endif + #if NR_PTYS == 0 #define pty_init(tp) ((void) 0) #define do_pty(tp, mp) ((void) 0) @@ -138,17 +139,21 @@ PUBLIC timer_t *tty_timers; /* queue of TTY timers */ PUBLIC clock_t tty_next_timeout; /* time that the next alarm is due */ PUBLIC struct machine machine; /* kernel environment variables */ +extern PUBLIC unsigned info_location; +extern PUBLIC phys_bytes vid_size; /* 0x2000 for color or 0x0800 for mono */ +extern PUBLIC phys_bytes vid_base; + + /*===========================================================================* * tty_task * *===========================================================================*/ -PUBLIC void main(void) +PUBLIC int main(void) { /* Main routine of the terminal task. */ message tty_mess; /* buffer for all incoming messages */ unsigned line; int r, s; - register struct proc *rp; register tty_t *tp; /* Get kernel environment (protected_mode, pc_at and ega are needed). */ @@ -162,9 +167,8 @@ PUBLIC void main(void) /* Final one-time keyboard initialization. */ kb_init_once(); - printf("\n"); - while (TRUE) { + int adflag = 0; /* Check for and handle any events on any of the ttys. */ for (tp = FIRST_TTY; tp < END_TTY; tp++) { @@ -212,14 +216,16 @@ PUBLIC void main(void) continue; } case DIAGNOSTICS: /* a server wants to print some */ +#if 0 if (tty_mess.m_source != LOG_PROC_NR) { - printf("WARNING: old DIAGNOSTICS from %d\n", - tty_mess.m_source); + printf("[%d ", tty_mess.m_source); } +#endif do_diagnostics(&tty_mess, 0); continue; case DIAGNOSTICS_S: + case ASYN_DIAGNOSTICS: do_diagnostics(&tty_mess, 1); continue; case GET_KMESS: @@ -299,6 +305,8 @@ PUBLIC void main(void) tty_mess.IO_ENDPT, EINVAL); } } + + return 0; } /*===========================================================================* @@ -397,7 +405,7 @@ register message *m_ptr; /* pointer to message sent to the task */ int safe; /* use safecopies? */ { /* A process wants to read from a terminal. */ - int r, status; + int r; /* Check if there is already a process hanging in a read, check if the * parameters are correct, do I/O. @@ -775,9 +783,6 @@ message *m_ptr; /* pointer to message sent to task */ if ((mode & W_BIT) && tp->tty_outleft != 0 && proc_nr == tp->tty_outproc && (!tp->tty_out_safe || tp->tty_out_vir_g==(vir_bytes)m_ptr->IO_GRANT)) { /* Process was writing when killed. Clean up output. */ -#if DEAD_CODE - (*tp->tty_ocancel)(tp, 0); -#endif r = tp->tty_outcum > 0 ? tp->tty_outcum : EAGAIN; tp->tty_outleft = tp->tty_outcum = tp->tty_outrevived = 0; } @@ -849,9 +854,6 @@ tty_t *tp; /* TTY to check for events. */ * messages (in proc.c). This is handled by explicitly checking each line * for fresh input and completed output on each interrupt. */ - char *buf; - unsigned count; - int status; do { tp->tty_events = 0; @@ -989,7 +991,6 @@ int count; /* number of input characters */ int ch, sig, ct; int timeset = FALSE; - static unsigned char csize_mask[] = { 0x1F, 0x3F, 0x7F, 0xFF }; for (ct = 0; ct < count; ct++) { /* Take one character. */ @@ -1373,7 +1374,7 @@ tty_t *tp; * sure that an attribute change doesn't affect the processing of current * output. Once output finishes the ioctl is executed as in do_ioctl(). */ - int result; + int result = EINVAL; if (tp->tty_outleft > 0) return; /* output not finished */ @@ -1535,8 +1536,6 @@ PRIVATE void tty_init() register tty_t *tp; int s; - struct sigaction sa; - char env[100]; /* Initialize the terminal lines. */ for (tp = FIRST_TTY,s=0; tp < END_TTY; tp++,s++) { @@ -1566,25 +1565,6 @@ PRIVATE void tty_init() tp->tty_minor = s - (NR_CONS+NR_RS_LINES) + TTYPX_MINOR; } } - - if(env_get_param("sticky_alt", env, sizeof(env)-1) == OK - && atoi(env) == 1) { - sticky_alt_mode = 1; - } - - -#if DEAD_CODE - /* Install signal handlers. Ask PM to transform signal into message. */ - sa.sa_handler = SIG_MESS; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - if (sigaction(SIGTERM,&sa,NULL)<0) panic("TTY","sigaction failed", errno); - if (sigaction(SIGKMESS,&sa,NULL)<0) panic("TTY","sigaction failed", errno); - if (sigaction(SIGKSTOP,&sa,NULL)<0) panic("TTY","sigaction failed", errno); -#endif -#if DEBUG - printf("end of tty_init\n"); -#endif } /*===========================================================================* @@ -1670,6 +1650,7 @@ tty_t *tp; int try; { /* Some functions need not be implemented at the device level. */ + return 0; } /*===========================================================================* diff --git a/drivers/tty/tty.h b/drivers/tty/tty.h index 2f3f24c9d..22c059d2c 100644 --- a/drivers/tty/tty.h +++ b/drivers/tty/tty.h @@ -1,8 +1,6 @@ /* tty.h - Terminals */ #include -#include "../../kernel/const.h" -#include "../../kernel/type.h" #undef lock #undef unlock @@ -115,8 +113,6 @@ extern unsigned long rs_irq_set; extern int panicing; /* From panic.c in sysutil */ -extern int sticky_alt_mode; /* right-alt sticky to switch codepages */ - /* Values for the fields. */ #define NOT_ESCAPED 0 /* previous character is not LNEXT (^V) */ #define ESCAPED 1 /* previous character was LNEXT (^V) */ diff --git a/etc/drivers.conf b/etc/drivers.conf index d16b93309..61707fc3f 100644 --- a/etc/drivers.conf +++ b/etc/drivers.conf @@ -163,6 +163,7 @@ driver is GETINFO # 26 SETGRANT # 34 ; + uid 0; }; driver pci @@ -217,7 +218,9 @@ driver mfs TIMES # 25 SAFECOPYFROM # 31 SAFECOPYTO # 32 + GETINFO SETGRANT # 34 + UMAP # 14 ; uid 0; }; diff --git a/etc/make.conf b/etc/make.conf index da18f0fbe..890f9eb07 100644 --- a/etc/make.conf +++ b/etc/make.conf @@ -1 +1,3 @@ +# which architecture to compile for ARCH=i386 + diff --git a/etc/rc b/etc/rc index 2578ad5a2..763c680fe 100755 --- a/etc/rc +++ b/etc/rc @@ -42,7 +42,6 @@ esac case $action in start) - echo "" echo -n "Multiuser startup in progress ...:" # National keyboard? diff --git a/include/minix/com.h b/include/minix/com.h index 6317ba6ff..108b0a195 100755 --- a/include/minix/com.h +++ b/include/minix/com.h @@ -36,13 +36,15 @@ /* User-space processes, that is, device drivers, servers, and INIT. */ #define PM_PROC_NR 0 /* process manager */ #define FS_PROC_NR 1 /* file system */ -#define RS_PROC_NR 2 /* reincarnation server */ +#define VFS_PROC_NR FS_PROC_NR /* FS has been renamed to VFS. */ +#define RS_PROC_NR 2 /* memory driver (RAM disk, null, etc.) */ #define MEM_PROC_NR 3 /* memory driver (RAM disk, null, etc.) */ #define LOG_PROC_NR 4 /* log device driver */ #define TTY_PROC_NR 5 /* terminal (TTY) driver */ #define DS_PROC_NR 6 /* data store server */ #define MFS_PROC_NR 7 /* minix root filesystem */ -#define INIT_PROC_NR 8 /* init -- goes multiuser */ +#define VM_PROC_NR 8 /* memory server */ +#define INIT_PROC_NR 9 /* init -- goes multiuser */ /* Number of processes contained in the system image. */ #define NR_BOOT_PROCS (NR_TASKS + INIT_PROC_NR + 1) @@ -166,6 +168,7 @@ #define DEV_SCATTER_S (DEV_RQ_BASE + 22) /* (safecopy) write from a vector */ #define DEV_GATHER_S (DEV_RQ_BASE + 23) /* (safecopy) read into a vector */ #define DEV_IOCTL_S (DEV_RQ_BASE + 24) /* (safecopy) I/O control code */ +#define DEV_MMAP_S (DEV_RQ_BASE + 25) /* (safecopy) mmap interface */ #define DEV_REPLY (DEV_RS_BASE + 0) /* general task reply */ #define DEV_CLONED (DEV_RS_BASE + 1) /* return cloned minor */ @@ -309,7 +312,6 @@ # define SYS_ABORT (KERNEL_CALL + 27) /* sys_abort() */ # define SYS_IOPENABLE (KERNEL_CALL + 28) /* sys_enable_iop() */ # define SYS_VM_SETBUF (KERNEL_CALL + 29) /* sys_vm_setbuf() */ -# define SYS_VM_MAP (KERNEL_CALL + 30) /* sys_vm_map() */ # define SYS_SAFECOPYFROM (KERNEL_CALL + 31) /* sys_safecopyfrom() */ # define SYS_SAFECOPYTO (KERNEL_CALL + 32) /* sys_safecopyto() */ # define SYS_VSAFECOPY (KERNEL_CALL + 33) /* sys_vsafecopy() */ @@ -323,8 +325,9 @@ # define SYS_STIME (KERNEL_CALL + 39) /* sys_stime() */ # define SYS_MAPDMA (KERNEL_CALL + 42) /* sys_mapdma() */ +# define SYS_VMCTL (KERNEL_CALL + 43) /* sys_vmctl() */ -#define NR_SYS_CALLS 43 /* number of system calls */ +#define NR_SYS_CALLS 44 /* number of system calls */ /* Pseudo call for use in kernel/table.c. */ #define SYS_ALL_CALLS (NR_SYS_CALLS) @@ -455,12 +458,18 @@ # define GET_LOADINFO 15 /* get load average information */ # define GET_IRQACTIDS 16 /* get the IRQ masks */ # define GET_PRIVID 17 /* get ID of privilege structure */ +# define GET_HZ 18 /* get HZ value */ +# define GET_WHOAMI 19 /* get own name and endpoint */ #define I_ENDPT m7_i4 /* calling process */ #define I_VAL_PTR m7_p1 /* virtual address at caller */ #define I_VAL_LEN m7_i1 /* max length of value */ #define I_VAL_PTR2 m7_p2 /* second virtual address */ #define I_VAL_LEN2_E m7_i2 /* second length, or proc nr */ +/* GET_WHOAMI fields. */ +#define GIWHO_EP m3_i1 +#define GIWHO_NAME m3_ca1 + /* Field names for SYS_TIMES. */ #define T_ENDPT m4_l1 /* process to request time info for */ #define T_USER_TIME m4_l1 /* user time consumed by process */ @@ -514,10 +523,14 @@ #define PR_MEM_PTR m1_p1 /* tells where memory map is for sys_newmap * and sys_fork */ +#define PR_FORK_FLAGS m1_i3 /* Field names for SYS_INT86 */ #define INT86_REG86 m1_p1 /* pointer to registers */ +/* Flags for PR_FORK_FLAGS. */ +#define PFF_VMINHIBIT 0x01 /* Don't schedule until release by VM. */ + /* Field names for SYS_SAFECOPY* */ #define SCP_FROM_TO m2_i1 /* from/to whom? */ #define SCP_INFO m2_i2 /* byte: DDDDSSSS Dest and Src seg */ @@ -559,6 +572,26 @@ #define RDB_ADDR m2_l1 #define RDB_BUF m2_p1 +/* Field names for SYS_VMCTL. */ +#define SVMCTL_WHO m1_i1 +#define SVMCTL_PARAM m1_i2 /* All SYS_VMCTL requests. */ +#define SVMCTL_VALUE m1_i3 +#define SVMCTL_PF_WHO m1_i1 /* GET_PAGEFAULT reply: process ep */ +#define SVMCTL_PF_I386_CR2 m1_i2 /* GET_PAGEFAULT reply: CR2 */ +#define SVMCTL_PF_I386_ERR m1_i3 /* GET_PAGEFAULT reply: error code */ +#define SVMCTL_MRG_ADDR m1_p1 /* MEMREQ_GET reply: address */ +#define SVMCTL_MRG_LEN m1_i1 /* MEMREQ_GET reply: length */ +#define SVMCTL_MRG_WRITE m1_i2 /* MEMREQ_GET reply: writeflag */ +#define SVMCTL_MRG_EP m1_i3 /* MEMREQ_GET reply: process */ + +/* Values for SVMCTL_PARAM. */ +#define VMCTL_I386_SETCR3 10 +#define VMCTL_GET_PAGEFAULT 11 +#define VMCTL_CLEAR_PAGEFAULT 12 +#define VMCTL_I386_GETCR3 13 +#define VMCTL_MEMREQ_GET 14 +#define VMCTL_MEMREQ_REPLY 15 + /*===========================================================================* * Messages for the Reincarnation Server * *===========================================================================*/ @@ -626,6 +659,7 @@ # define GETKM_PTR m1_p1 #define GET_KMESS_S (DIAG_BASE+4) /* get kmess from TTY */ # define GETKM_GRANT m1_i1 +#define ASYN_DIAGNOSTICS (DIAG_BASE+5) /* grant-based, replyless DIAGNOSTICS */ #define DIAG_REPL (DIAG_BASE+0x80+0) /* reply to DIAGNOSTICS(_S) */ @@ -695,6 +729,7 @@ * FS to update its uid and gid * fields. */ +#define EXC_NM_RF_FULLVM 4 /* Parameters for the EXEC_RESTART call */ #define EXC_RS_PROC m1_i1 /* process that needs to be restarted */ @@ -704,4 +739,115 @@ * implementations. See */ +/* Requests sent by VM to VFS, done on behalf of a user process. */ +#define VM_VFS_BASE 0xB00 +#define VM_VFS_OPEN (VM_VFS_BASE+0) /* open() on behalf of user process. */ +# define VMVO_NAME_GRANT m2_i1 /* 0-terminated */ +# define VMVO_NAME_LENGTH m2_i2 /* name length including 0 */ +# define VMVO_FLAGS m2_i3 +# define VMVO_MODE m2_l1 +# define VMVO_ENDPOINT m2_l2 +#define VM_VFS_MMAP (VM_VFS_BASE+1) /* mmap() */ +#define VM_VFS_CLOSE (VM_VFS_BASE+2) /* close() */ +# define VMVC_FD m1_i1 +# define VMVC_ENDPOINT m1_i2 + +/*===========================================================================* + * Messages for VM server * + *===========================================================================*/ +#define VM_RQ_BASE 0xC00 + +/* Calls from PM */ +#define VM_EXIT (VM_RQ_BASE+0) +# define VME_ENDPOINT m1_i1 +#define VM_FORK (VM_RQ_BASE+1) +# define VMF_ENDPOINT m1_i1 +# define VMF_SLOTNO m1_i2 +# define VMF_CHILD_ENDPOINT m1_i3 /* result */ +#define VM_BRK (VM_RQ_BASE+2) +# define VMB_ENDPOINT m1_i1 +# define VMB_ADDR m1_p1 +# define VMB_RETADDR m1_p2 /* result */ +#define VM_EXEC_NEWMEM (VM_RQ_BASE+3) +# define VMEN_ENDPOINT m1_i1 +# define VMEN_ARGSPTR m1_p1 +# define VMEN_ARGSSIZE m1_i2 +# define VMEN_FLAGS m1_i3 /* result */ +# define VMEN_STACK_TOP m1_p2 /* result */ +#define VM_PUSH_SIG (VM_RQ_BASE+4) +# define VMPS_ENDPOINT m1_i1 +# define VMPS_OLD_SP m1_p1 /* result */ +#define VM_WILLEXIT (VM_RQ_BASE+5) +# define VMWE_ENDPOINT m1_i1 + +/* General calls. */ +#define VM_MMAP (VM_RQ_BASE+10) +# define VMM_ADDR m5_l1 +# define VMM_LEN m5_l2 +# define VMM_PROT m5_c1 +# define VMM_FLAGS m5_c2 +# define VMM_FD m5_i1 +# define VMM_OFFSET m5_i2 +# define VMM_RETADDR m5_l1 /* result */ +#define VM_UMAP (VM_RQ_BASE+11) +# define VMU_SEG m1_i1 +# define VMU_OFFSET m1_p1 +# define VMU_LENGTH m1_p2 +# define VMU_RETADDR m1_p3 + +/* to VM: inform VM about a region of memory that is used for + * bus-master DMA + */ +#define VM_ADDDMA (VM_RQ_BASE+12) +# define VMAD_REQ m2_i2 +# define VMAD_EP m2_i1 +# define VMAD_START m2_l1 +# define VMAD_SIZE m2_l2 + +/* to VM: inform VM that a region of memory that is no longer + * used for bus-master DMA + */ +#define VM_DELDMA (VM_RQ_BASE+13) +# define VMDD_REQ m2_i2 +# define VMDD_EP m2_i1 +# define VMDD_START m2_l1 +# define VMDD_SIZE m2_l2 + +/* to VM: ask VM for a region of memory that should not + * be used for bus-master DMA any longer + */ +#define VM_GETDMA (VM_RQ_BASE+14) +# define VMGD_REQ m2_i2 +# define VMGD_PROCP m2_i1 +# define VMGD_BASEP m2_l1 +# define VMGD_SIZEP m2_l2 + +#define VM_MAP_PHYS (VM_RQ_BASE+15) +# define VMMP_EP m1_i1 +# define VMMP_PHADDR m1_p2 +# define VMMP_LEN m1_i2 +# define VMMP_VADDR_REPLY m1_p3 + +#define VM_UNMAP_PHYS (VM_RQ_BASE+16) +# define VMUP_EP m1_i1 +# define VMUP_VADDR m1_p1 + +#define VM_UNMAP (VM_RQ_BASE+17) +# define VMUM_ADDR m1_p1 +# define VMUM_LEN m1_i1 + +#define VM_ALLOCMEM (VM_RQ_BASE+18) +# define VMAM_CLICKS m1_p1 +# define VMAM_MEMBASE m1_i1 + +/* Calls from VFS. */ +# define VMV_ENDPOINT m1_i1 /* for all VM_VFS_REPLY_* */ +#define VM_VFS_REPLY_OPEN (VM_RQ_BASE+30) +# define VMVRO_FD m1_i2 +#define VM_VFS_REPLY_MMAP (VM_RQ_BASE+31) +#define VM_VFS_REPLY_CLOSE (VM_RQ_BASE+32) + +/* Total. */ +#define VM_NCALLS 33 + #endif /* _MINIX_COM_H */ diff --git a/include/minix/config.h b/include/minix/config.h index b0686f3c8..8bac14ba4 100755 --- a/include/minix/config.h +++ b/include/minix/config.h @@ -39,45 +39,9 @@ #define NR_PROCS _NR_PROCS #define NR_SYS_PROCS _NR_SYS_PROCS -#if _MINIX_SMALL - -#define NR_BUFS 100 -#define NR_BUF_HASH 128 - -#else - -/* The buffer cache should be made as large as you can afford. */ -#if (MACHINE == IBM_PC && _WORD_SIZE == 2) -#define NR_BUFS 40 /* # blocks in the buffer cache */ -#define NR_BUF_HASH 64 /* size of buf hash table; MUST BE POWER OF 2*/ -#endif - -#if (MACHINE == IBM_PC && _WORD_SIZE == 4) -#define NR_BUFS 1200 /* # blocks in the buffer cache */ -#define NR_BUF_HASH 2048 /* size of buf hash table; MUST BE POWER OF 2*/ -#endif - -#if (MACHINE == SUN_4_60) -#define NR_BUFS 512 /* # blocks in the buffer cache (<=1536) */ -#define NR_BUF_HASH 512 /* size of buf hash table; MUST BE POWER OF 2*/ -#endif - -#endif /* _MINIX_SMALL */ - /* Number of controller tasks (/dev/cN device classes). */ #define NR_CTRLRS 2 -/* Enable or disable the second level file system cache on the RAM disk. */ -#define ENABLE_CACHE2 0 - -/* Enable or disable swapping processes to disk. */ -#define ENABLE_SWAP 0 - -/* Include or exclude an image of /dev/boot in the boot image. - * Please update the makefile in /usr/src/tools/ as well. - */ -#define ENABLE_BOOTDEV 0 /* load image of /dev/boot at boot time */ - /* DMA_SECTORS may be increased to speed up DMA based drivers. */ #define DMA_SECTORS 1 /* DMA buffer size (must be >= 1) */ diff --git a/include/minix/const.h b/include/minix/const.h index 57d35deb3..a26716b15 100755 --- a/include/minix/const.h +++ b/include/minix/const.h @@ -11,7 +11,7 @@ #define TRUE 1 /* used for turning integers into Booleans */ #define FALSE 0 /* used for turning integers into Booleans */ -#define HZ 60 /* clock freq (software settable on IBM-PC) */ +#define HZ 600 /* clock freq (software settable on IBM-PC) */ #define SUPER_USER (uid_t) 0 /* uid_t of superuser */ @@ -19,7 +19,7 @@ #define CPVEC_NR 16 /* max # of entries in a SYS_VCOPY request */ #define CPVVEC_NR 64 /* max # of entries in a SYS_VCOPY request */ #define SCPVEC_NR 64 /* max # of entries in a SYS_VSAFECOPY* request */ -#define NR_IOREQS MIN(NR_BUFS, 64) +#define NR_IOREQS 64 /* maximum number of entries in an iorequest */ /* Message passing constants. */ @@ -46,6 +46,12 @@ #define GRANT_SEG 0x0800 /* flag indicating grant for umap */ +#define LOCAL_VM_SEG 0x1000 /* same as LOCAL_SEG, but with vm lookup */ +#define VM_D (LOCAL_VM_SEG | D) +#define VM_T (LOCAL_VM_SEG | T) +#define MEM_GRANT 3 +#define VM_GRANT (LOCAL_VM_SEG | MEM_GRANT) + /* Labels used to disable code sections for different reasons. */ #define DEAD_CODE 0 /* unused code in normal configuration */ #define FUTURE_CODE 0 /* new code to be activated + tested later */ @@ -77,6 +83,13 @@ #define CLICK_SHIFT 12 /* log2 of CLICK_SIZE */ #endif +/* Sizes of memory tables. The boot monitor distinguishes three memory areas, + * namely low mem below 1M, 1M-16M, and mem after 16M. More chunks are needed + * for DOS MINIX. +*/ +#define NR_MEMS 8 + + /* Click to byte conversions (and vice versa). */ #define HCLICK_SHIFT 4 /* log2 of HCLICK_SIZE */ #define HCLICK_SIZE 16 /* hardware segment conversion magic */ @@ -108,8 +121,6 @@ #define I_NOT_ALLOC 0000000 /* this inode is free */ /* Some limits. */ -#define MAX_BLOCK_NR ((block_t) 077777777) /* largest block number */ -#define HIGHEST_ZONE ((zone_t) 077777777) /* largest zone number */ #define MAX_INODE_NR ((ino_t) 037777777777) /* largest inode number */ #define MAX_FILE_POS ((off_t) 0x7FFFFFFF) /* largest legal file offset */ diff --git a/include/minix/devio.h b/include/minix/devio.h index e123f8521..8ce9b8aa9 100644 --- a/include/minix/devio.h +++ b/include/minix/devio.h @@ -29,8 +29,8 @@ typedef struct { u16_t port; u32_t value; } pvl_pair_t; (pv).port = _p; \ (pv).value = _v; \ if((pv).port != _p || (pv).value != _v) { \ - printf("%s:%d: actual port: %x != %x || " \ - "actual value: %x != %x\n", \ + printf("%s:%d: actual port: 0x%x != 0x%lx || " \ + "actual value: 0x%x != 0x%lx\n", \ __FILE__, __LINE__, (pv).port, _p, (pv).value, _v); \ panic(__FILE__, "pv_set(" #pv ", " #p ", " #v ")", NO_NUM); \ } \ diff --git a/include/minix/ipc.h b/include/minix/ipc.h index 1eef6fb1e..8f6618927 100644 --- a/include/minix/ipc.h +++ b/include/minix/ipc.h @@ -1,6 +1,8 @@ #ifndef _IPC_H #define _IPC_H +#include + /*==========================================================================* * Types relating to messages. * *==========================================================================*/ diff --git a/include/minix/sys_config.h b/include/minix/sys_config.h index 97fea6fee..c0fd599c0 100755 --- a/include/minix/sys_config.h +++ b/include/minix/sys_config.h @@ -20,7 +20,6 @@ #define _NR_PROCS 100 #define _NR_SYS_PROCS 32 -#define _NR_HOLES (2*_NR_PROCS+4) /* No. of memory holes maintained by PM */ /* Set the CHIP type based on the machine selected. The symbol CHIP is actually * indicative of more than just the CPU. For example, machines for which @@ -71,4 +70,6 @@ error "_MINIX_MACHINE has incorrect value (0)" /* Kernel debug checks */ #define DEBUG_LOCK_CHECK 1 /* Interrupt Lock/unlock sanity checking. */ +#define _KMESS_BUF_SIZE 30000 + #endif /* _MINIX_SYS_CONFIG_H */ diff --git a/include/minix/syslib.h b/include/minix/syslib.h index 77a1e4e8f..bdc2fcbbd 100755 --- a/include/minix/syslib.h +++ b/include/minix/syslib.h @@ -34,7 +34,8 @@ _PROTOTYPE( int sys_abort, (int how, ...)); _PROTOTYPE( int sys_enable_iop, (endpoint_t proc)); _PROTOTYPE( int sys_exec, (endpoint_t proc, char *ptr, char *aout, vir_bytes initpc)); -_PROTOTYPE( int sys_fork, (int parent, int child, int *, struct mem_map *ptr)); +_PROTOTYPE( int sys_fork, (endpoint_t parent, endpoint_t child, int *, + struct mem_map *ptr, u32_t vm)); _PROTOTYPE( int sys_newmap, (endpoint_t proc, struct mem_map *ptr)); _PROTOTYPE( int sys_exit, (endpoint_t proc)); _PROTOTYPE( int sys_trace, (int req, endpoint_t proc, long addr, long *data_p)); @@ -48,6 +49,13 @@ _PROTOTYPE( int sys_vm_setbuf, (phys_bytes base, phys_bytes size, phys_bytes high)); _PROTOTYPE( int sys_vm_map, (endpoint_t proc_nr, int do_map, phys_bytes base, phys_bytes size, phys_bytes offset)); +_PROTOTYPE( int sys_vmctl, (endpoint_t who, int param, u32_t value)); +_PROTOTYPE( int sys_vmctl_get_pagefault_i386, (endpoint_t *who, u32_t *cr2, u32_t *err)); +_PROTOTYPE( int sys_vmctl_get_cr3_i386, (endpoint_t who, u32_t *cr3) ); +_PROTOTYPE( int sys_vmctl_get_memreq, (endpoint_t *who, vir_bytes *mem, + vir_bytes *len, int *wrflag) ); + + _PROTOTYPE( int sys_readbios, (phys_bytes address, void *buf, size_t size)); _PROTOTYPE( int sys_stime, (time_t boottime)); @@ -71,6 +79,9 @@ _PROTOTYPE( int sys_stime, (time_t boottime)); sys_sdevio(DIO_SAFE_OUTPUT_WORD, port, ept, (void*)grant, count, offset) _PROTOTYPE( int sys_sdevio, (int req, long port, endpoint_t proc_nr, void *buffer, int count, vir_bytes offset)); +_PROTOTYPE(void *alloc_contig, (size_t len, int flags, phys_bytes *phys)); +#define AC_ALIGN4K 0x01 +#define AC_LOWER16M 0x02 /* Clock functionality: get system times or (un)schedule an alarm call. */ _PROTOTYPE( int sys_times, (endpoint_t proc_nr, clock_t *user_time, @@ -128,6 +139,8 @@ _PROTOTYPE(int sys_physvcopy, (phys_cp_req *vec_ptr,int vec_size,int *nr_ok)); _PROTOTYPE(int sys_umap, (endpoint_t proc_nr, int seg, vir_bytes vir_addr, vir_bytes bytes, phys_bytes *phys_addr)); +_PROTOTYPE(int sys_umap_data_fb, (endpoint_t proc_nr, vir_bytes vir_addr, + vir_bytes bytes, phys_bytes *phys_addr)); _PROTOTYPE(int sys_segctl, (int *index, u16_t *seg, vir_bytes *off, phys_bytes phys, vir_bytes size)); @@ -151,6 +164,7 @@ _PROTOTYPE(int sys_segctl, (int *index, u16_t *seg, vir_bytes *off, #define sys_getprivid(nr) sys_getinfo(GET_PRIVID, 0, 0,0, nr) _PROTOTYPE(int sys_getinfo, (int request, void *val_ptr, int val_len, void *val_ptr2, int val_len2) ); +_PROTOTYPE(int sys_whoami, (endpoint_t *ep, char *name, int namelen)); /* Signal control. */ _PROTOTYPE(int sys_kill, (endpoint_t proc, int sig) ); diff --git a/include/minix/sysutil.h b/include/minix/sysutil.h index 8702ea8c2..2af9bbc05 100644 --- a/include/minix/sysutil.h +++ b/include/minix/sysutil.h @@ -1,6 +1,8 @@ #ifndef _MINIX_SYSUTIL_H #define _MINIX_SYSUTIL_H 1 +#include + /* Extra system library definitions to support device drivers and servers. * * Created: @@ -48,9 +50,15 @@ _PROTOTYPE( int getuptime, (clock_t *ticks)); _PROTOTYPE( int getuptime2, (clock_t *ticks, time_t *boottime)); _PROTOTYPE( int tickdelay, (clock_t ticks)); _PROTOTYPE( int micro_delay_calibrate, (void)); +_PROTOTYPE( u32_t sys_hz, (void)); +_PROTOTYPE( void util_stacktrace, (void)); +_PROTOTYPE( void util_nstrcat, (char *str, unsigned long n) ); +_PROTOTYPE( void util_stacktrace_strcat, (char *)); _PROTOTYPE( int micro_delay, (u32_t micros)); +_PROTOTYPE( u32_t micros_to_ticks, (u32_t micros)); +_PROTOTYPE( int asynsend, (endpoint_t ep, message *msg)); -#define MICROS_TO_TICKS(m) (((m)*HZ/1000000)+1) +#define ASSERT(c) if(!(c)) { panic(__FILE__, "assert " #c " failed at line", __LINE__); } #endif /* _MINIX_SYSUTIL_H */ diff --git a/include/minix/tty.h b/include/minix/tty.h new file mode 100644 index 000000000..fcf8d2f97 --- /dev/null +++ b/include/minix/tty.h @@ -0,0 +1,28 @@ + +#ifndef _MINIX_TTY_H +#define _MINIX_TTY_H + +#include + +#define TTYMAGIC 0xb105 + +/* A struct that the tty driver can use to pass values to the boot monitor. + * Currently only the value of the origin of the first vty (console), so the + * boot monitor can properly display it when panicing (tty isn't scheduled + * to switch to the first vty). It's written at the end of video memory + * (video memory base + video memory size - sizeof(struct boot_tty_info). + */ + +struct boot_tty_info { + u16_t reserved[30]; /* reserved, set to 0 */ + u16_t consorigin; /* origin in video memory of console */ + u16_t conscursor; /* position of cursor of console */ + u16_t flags; /* flags indicating which fields are valid */ + u16_t magic; /* magic number indicating struct is valid */ +}; + +#define BTIF_CONSORIGIN 0x01 /* consorigin is set */ +#define BTIF_CONSCURSOR 0x02 /* conscursor is set */ + +#endif + diff --git a/include/minix/type.h b/include/minix/type.h index 08582c253..8be6b33a6 100755 --- a/include/minix/type.h +++ b/include/minix/type.h @@ -16,7 +16,7 @@ typedef unsigned int phys_clicks; /* physical addr/length in clicks */ typedef int endpoint_t; /* process identifier */ #if (_MINIX_CHIP == _CHIP_INTEL) -typedef unsigned int vir_bytes; /* virtual addresses and lengths in bytes */ +typedef long unsigned int vir_bytes; /* virtual addresses/lengths in bytes */ #endif #if (_MINIX_CHIP == _CHIP_M68000) @@ -48,19 +48,6 @@ struct vir_addr { vir_bytes offset; }; -/* Memory allocation by PM. */ -struct hole { - struct hole *h_next; /* pointer to next entry on the list */ - phys_clicks h_base; /* where does the hole begin? */ - phys_clicks h_len; /* how big is the hole? */ -}; - -/* Memory info from PM. */ -struct pm_mem_info { - struct hole pmi_holes[_NR_HOLES];/* memory (un)allocations */ - u32_t pmi_hi_watermark; /* highest ever-used click + 1 */ -}; - #define phys_cp_req vir_cp_req struct vir_cp_req { struct vir_addr src; @@ -98,14 +85,14 @@ struct kinfo { phys_bytes data_base; /* base of kernel data */ phys_bytes data_size; vir_bytes proc_addr; /* virtual address of process table */ - phys_bytes kmem_base; /* kernel memory layout (/dev/kmem) */ - phys_bytes kmem_size; + phys_bytes _kmem_base; /* kernel memory layout (/dev/kmem) */ + phys_bytes _kmem_size; phys_bytes bootdev_base; /* boot device from boot image (/dev/boot) */ phys_bytes bootdev_size; phys_bytes ramdev_base; /* boot device from boot image (/dev/boot) */ phys_bytes ramdev_size; - phys_bytes params_base; /* parameters passed by boot monitor */ - phys_bytes params_size; + phys_bytes _params_base; /* parameters passed by boot monitor */ + phys_bytes _params_size; int nr_procs; /* number of user processes */ int nr_tasks; /* number of kernel tasks */ char release[6]; /* kernel release number */ @@ -176,4 +163,21 @@ struct memory { phys_bytes size; }; +#define STATICINIT(v, n) \ + if(!(v)) { \ + phys_bytes myph; \ + if(!((v) = alloc_contig(sizeof(*(v)) * (n), 0, &myph))) { \ + panic(__FILE__, "allocating " #v " failed", n); \ + } \ + } + +/* The kernel outputs diagnostic messages in a circular buffer. */ +struct kmessages { + int km_next; /* next index to write */ + int km_size; /* current size in buffer */ + char km_buf[_KMESS_BUF_SIZE]; /* buffer for messages */ +}; + + #endif /* _TYPE_H */ + diff --git a/include/minix/vm.h b/include/minix/vm.h new file mode 100755 index 000000000..475f49951 --- /dev/null +++ b/include/minix/vm.h @@ -0,0 +1,29 @@ +/* Prototypes and definitions for VM interface. */ + +#ifndef _MINIX_VM_H +#define _MINIX_VM_H + +#include +#include + +_PROTOTYPE( int vm_exit, (endpoint_t ep)); +_PROTOTYPE( int vm_fork, (endpoint_t ep, int slotno, int *child_ep)); +_PROTOTYPE( int vm_brk, (endpoint_t ep, char *newaddr)); +_PROTOTYPE( int vm_exec_newmem, (endpoint_t ep, struct exec_newmem *args, + int args_bytes, char **ret_stack_top, int *ret_flags)); +_PROTOTYPE( int vm_push_sig, (endpoint_t ep, vir_bytes *old_sp)); +_PROTOTYPE( int vm_willexit, (endpoint_t ep)); +_PROTOTYPE( int vm_adddma, (endpoint_t req_e, endpoint_t proc_e, + phys_bytes start, phys_bytes size) ); +_PROTOTYPE( int vm_deldma, (endpoint_t req_e, endpoint_t proc_e, + phys_bytes start, phys_bytes size) ); +_PROTOTYPE( int vm_getdma, (endpoint_t req_e, endpoint_t *procp, + phys_bytes *basep, phys_bytes *sizep) ); +_PROTOTYPE( void *vm_map_phys, (endpoint_t who, size_t len, void *physaddr)); +_PROTOTYPE( int vm_unmap_phys, (endpoint_t who, void *vaddr, size_t len)); + +_PROTOTYPE( int vm_allocmem, (phys_clicks memclicks, phys_clicks *retmembase)); + + +#endif /* _MINIX_VM_H */ + diff --git a/include/sys/ioc_tty.h b/include/sys/ioc_tty.h index 948a41e09..c37972443 100755 --- a/include/sys/ioc_tty.h +++ b/include/sys/ioc_tty.h @@ -36,4 +36,8 @@ #define KIOCSLEDS _IOW('k', 2, struct kio_leds) #define KIOCSMAP _IOW('k', 3, keymap_t) +/* /dev/video ioctls. */ +#define TIOCMAPMEM _IORW('v', 1, struct mapreqvm) +#define TIOCUNMAPMEM _IORW('v', 2, struct mapreqvm) + #endif /* _S_I_TTY_H */ diff --git a/include/sys/mman.h b/include/sys/mman.h new file mode 100755 index 000000000..1c3ef37a2 --- /dev/null +++ b/include/sys/mman.h @@ -0,0 +1,29 @@ + +#ifndef _MMAN_H +#define _MMAN_H + +#ifndef _TYPES_H +#include +#endif + +/* prot argument for mmap() */ +#define PROT_NONE 0x00 /* no permissions */ +#define PROT_READ 0x01 /* pages can be read */ +#define PROT_WRITE 0x02 /* pages can be written */ +#define PROT_EXEC 0x04 /* pages can be executed */ + +/* flags argument for mmap() */ +#define MAP_SHARED 0x0001 /* share changes */ +#define MAP_PRIVATE 0x0002 /* changes are private */ +#define MAP_ANON 0x0004 /* anonymous memory */ +#define MAP_PREALLOC 0x0008 /* not on-demand */ +#define MAP_CONTIG 0x0010 /* contiguous in physical memory */ +#define MAP_LOWER16M 0x0020 /* physically below 16MB */ + +/* mmap() error return */ +#define MAP_FAILED ((void *)-1) + +_PROTOTYPE( void *mmap, (void *, size_t, int, int, int, off_t)); +_PROTOTYPE( int munmap, (void *, size_t)); + +#endif /* _MMAN_H */ diff --git a/include/sys/video.h b/include/sys/video.h new file mode 100644 index 000000000..f6f425ed7 --- /dev/null +++ b/include/sys/video.h @@ -0,0 +1,39 @@ + +#ifndef _SYS_VIDEO_H +#define _SYS_VIDEO_H 1 + +/* Definitions used by the console driver. */ +#define MONO_BASE 0xB0000L /* base of mono video memory */ +#define COLOR_BASE 0xB8000L /* base of color video memory */ +#define MONO_SIZE 0x1000 /* 4K mono video memory */ +#define COLOR_SIZE 0x4000 /* 16K color video memory */ +#define EGA_SIZE 0x8000 /* EGA & VGA have at least 32K */ +#define BLANK_COLOR 0x0700 /* determines cursor color on blank screen */ +#define SCROLL_UP 0 /* scroll forward */ +#define SCROLL_DOWN 1 /* scroll backward */ +#define BLANK_MEM ((u16_t *) 0) /* tells mem_vid_copy() to blank the screen */ +#define CONS_RAM_WORDS 80 /* video ram buffer size */ +#define MAX_ESC_PARMS 4 /* number of escape sequence params allowed */ + +/* Constants relating to the controller chips. */ +#define M_6845 0x3B4 /* port for 6845 mono */ +#define C_6845 0x3D4 /* port for 6845 color */ +#define INDEX 0 /* 6845's index register */ +#define DATA 1 /* 6845's data register */ +#define STATUS 6 /* 6845's status register */ +#define VID_ORG 12 /* 6845's origin register */ +#define CURSOR 14 /* 6845's cursor register */ + +/* Beeper. */ +#define BEEP_FREQ 0x0533 /* value to put into timer to set beep freq */ +#define B_TIME 3 /* length of CTRL-G beep is ticks */ + +/* definitions used for font management */ +#define GA_SEQUENCER_INDEX 0x3C4 +#define GA_SEQUENCER_DATA 0x3C5 +#define GA_GRAPHICS_INDEX 0x3CE +#define GA_GRAPHICS_DATA 0x3CF +#define GA_VIDEO_ADDRESS 0xA0000L +#define GA_FONT_SIZE 8192 + +#endif diff --git a/include/sys/vm.h b/include/sys/vm.h index a5d95374b..b0155aa44 100644 --- a/include/sys/vm.h +++ b/include/sys/vm.h @@ -2,8 +2,6 @@ sys/vm.h */ -#define PAGE_SIZE 4096 - /* MIOCMAP */ struct mapreq { @@ -13,18 +11,14 @@ struct mapreq int readonly; }; -/* i386 paging constants */ -#define I386_VM_PRESENT 0x001 /* Page is present */ -#define I386_VM_WRITE 0x002 /* Read/write access allowed */ -#define I386_VM_USER 0x004 /* User access allowed */ -#define I386_VM_PWT 0x008 /* Write through */ -#define I386_VM_PCD 0x010 /* Cache disable */ -#define I386_VM_ADDR_MASK 0xFFFFF000 /* physical address */ -#define I386_VM_PT_ENT_SIZE 4 /* Size of a page table entry */ -#define I386_VM_DIR_ENTRIES 1024 /* Number of entries in a page dir */ -#define I386_VM_DIR_ENT_SHIFT 22 /* Shift to get entry in page dir. */ -#define I386_VM_PT_ENT_SHIFT 12 /* Shift to get entry in page table */ -#define I386_VM_PT_ENT_MASK 0x3FF /* Mask to get entry in page table */ - -#define I386_CR0_PG 0x80000000 /* Enable paging */ +/* MIOCMAPVM */ +struct mapreqvm +{ + int flags; /* reserved, must be 0 */ + off_t phys_offset; + size_t size; + int readonly; + char reserved[40]; /* reserved, must be 0 */ + void *vaddr_ret; /* result vaddr */ +}; diff --git a/include/sys/vm_i386.h b/include/sys/vm_i386.h new file mode 100644 index 000000000..dcea95b25 --- /dev/null +++ b/include/sys/vm_i386.h @@ -0,0 +1,45 @@ +/* +sys/vm_i386.h +*/ + +#define I386_PAGE_SIZE 4096 + +/* i386 paging constants */ +#define I386_VM_PRESENT 0x001 /* Page is present */ +#define I386_VM_WRITE 0x002 /* Read/write access allowed */ +#define I386_VM_USER 0x004 /* User access allowed */ +#define I386_VM_PWT 0x008 /* Write through */ +#define I386_VM_PCD 0x010 /* Cache disable */ +#define I386_VM_ACC 0x020 /* Accessed */ +#define I386_VM_ADDR_MASK 0xFFFFF000 /* physical address */ + +/* Page directory specific flags. */ +#define I386_VM_BIGPAGE 0x080 /* 4MB page */ + +/* Page table specific flags. */ +#define I386_VM_DIRTY 0x040 /* Dirty */ +#define I386_VM_PTAVAIL1 0x080 /* Available for use. */ +#define I386_VM_PTAVAIL2 0x100 /* Available for use. */ + +#define I386_VM_PT_ENT_SIZE 4 /* Size of a page table entry */ +#define I386_VM_DIR_ENTRIES 1024 /* Number of entries in a page dir */ +#define I386_VM_DIR_ENT_SHIFT 22 /* Shift to get entry in page dir. */ +#define I386_VM_PT_ENT_SHIFT 12 /* Shift to get entry in page table */ +#define I386_VM_PT_ENT_MASK 0x3FF /* Mask to get entry in page table */ +#define I386_VM_PT_ENTRIES 1024 /* Number of entries in a page table */ +#define I386_VM_PFA_SHIFT 22 /* Page frame address shift */ + +#define I386_CR0_PG 0x80000000 /* Enable paging */ + +/* i386 paging 'functions' */ +#define I386_VM_PTE(v) (((v) >> I386_VM_PT_ENT_SHIFT) & I386_VM_PT_ENT_MASK) +#define I386_VM_PDE(v) ( (v) >> I386_VM_DIR_ENT_SHIFT) +#define I386_VM_PFA(e) ( (e) & I386_VM_ADDR_MASK) +#define I386_VM_PAGE(v) ( (v) >> I386_VM_PFA_SHIFT) + +/* i386 pagefault error code bits */ +#define I386_VM_PFE_P 0x01 /* Pagefault caused by non-present page. + * (otherwise protection violation.) + */ +#define I386_VM_PFE_W 0x02 /* Caused by write (otherwise read) */ +#define I386_VM_PFE_U 0x04 /* CPU in user mode (otherwise supervisor) */ diff --git a/include/time.h b/include/time.h index 8cb0f3a8c..6915480e2 100755 --- a/include/time.h +++ b/include/time.h @@ -9,7 +9,7 @@ #ifndef _TIME_H #define _TIME_H -#define CLOCKS_PER_SEC 60 /* MINIX always uses 60 Hz, even in Europe */ +#define CLOCKS_PER_SEC 60 #ifdef _POSIX_SOURCE #define CLK_TCK CLOCKS_PER_SEC /* obsolescent mame for CLOCKS_PER_SEC */ diff --git a/include/tools.h b/include/tools.h index e1a81060d..b59e00ecb 100755 --- a/include/tools.h +++ b/include/tools.h @@ -1,3 +1,6 @@ +#ifndef _INCLUDE_TOOLS_H +#define _INCLUDE_TOOLS_H 1 + /* Constants describing the disk */ #define SECTOR_SIZE 512 #define SECTOR_SHIFT 9 @@ -121,3 +124,4 @@ _PROTOTYPE( void relocate, (void)); _PROTOTYPE( int writesectors, (int _off, int _seg, off_t _adr, int _ct)); #endif +#endif diff --git a/kernel/Makefile b/kernel/Makefile index f1e839735..407731a77 100755 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -18,21 +18,20 @@ CFLAGS=$(CPROFILE) $(CPPFLAGS) $(EXTRA_OPTS) LDFLAGS=-i # first-stage, arch-dependent startup code -HEAD = head.o -FULLHEAD = $a/$(HEAD) +HEAD = $a/mpx386.o OBJS = start.o table.o main.o proc.o \ system.o clock.o utility.o debug.o profile.o interrupt.o SYSTEM = system.a ARCHLIB = $a/$(ARCH).a -LIBS = -ltimers -lsysutil +LIBS = -ltimers -lsys # What to make. all: build -kernel build install: $(HEAD) $(OBJS) +kernel build install: $(OBJS) cd system && $(MAKE) $@ cd $a && $(MAKE) $@ - $(LD) $(CFLAGS) $(LDFLAGS) -o kernel $(FULLHEAD) $(OBJS) \ + $(LD) $(CFLAGS) $(LDFLAGS) -o kernel $(HEAD) $(OBJS) \ $(SYSTEM) $(ARCHLIB) $(LIBS) install -S 0 kernel @@ -50,8 +49,5 @@ depend: .c.o: $(CC) $(CFLAGS) -c -o $@ $< -$(HEAD): - cd $a && make HEAD=$(HEAD) $(HEAD) - # Include generated dependencies. include .depend diff --git a/kernel/arch/i386/Makefile b/kernel/arch/i386/Makefile index c7a5dc6a7..20d9181e4 100755 --- a/kernel/arch/i386/Makefile +++ b/kernel/arch/i386/Makefile @@ -8,17 +8,19 @@ ARCHAR=$(ARCH).a # the HEAD variable is passed as an argument to this Makefile # by an upper level Makefile. -OBJS=$(ARCHAR)(exception.o) \ - $(ARCHAR)(i8259.o) \ - $(ARCHAR)(memory.o) \ - $(ARCHAR)(protect.o) \ - $(ARCHAR)(system.o) \ - $(ARCHAR)(clock.o) \ - $(ARCHAR)(klib386.o) \ - $(ARCHAR)(do_readbios.o) \ - $(ARCHAR)(do_int86.o) \ - $(ARCHAR)(do_sdevio.o) \ - $(ARCHAR)(do_iopenable.o) +OBJS= arch_do_vmctl.o \ + clock.o \ + do_int86.o \ + do_iopenable.o \ + do_readbios.o \ + do_sdevio.o \ + exception.o \ + i8259.o \ + klib386.o \ + memory.o \ + mpx386.o \ + protect.o \ + system.o CPPFLAGS=-Iinclude CFLAGS=$(CPPFLAGS) -Wall @@ -56,6 +58,9 @@ $(ARCHAR)(do_int86.o): do_int86.c $(ARCHAR)(do_iopenable.o): do_iopenable.c $(CC) $(CFLAGS) -c $< +$(ARCHAR)(arch_do_vmctl.o): arch_do_vmctl.c + $(CC) $(CFLAGS) -c $< + $(ARCHAR)(do_readbios.o): do_readbios.c $(CC) $(CFLAGS) -c $< diff --git a/kernel/arch/i386/arch_do_vmctl.c b/kernel/arch/i386/arch_do_vmctl.c new file mode 100644 index 000000000..b82ce52a3 --- /dev/null +++ b/kernel/arch/i386/arch_do_vmctl.c @@ -0,0 +1,56 @@ +/* The kernel call implemented in this file: + * m_type: SYS_VMCTL + * + * The parameters for this kernel call are: + * SVMCTL_WHO which process + * SVMCTL_PARAM set this setting (VMCTL_*) + * SVMCTL_VALUE to this value + */ + +#include "../../system.h" +#include + +extern u32_t kernel_cr3; + +/*===========================================================================* + * arch_do_vmctl * + *===========================================================================*/ +PUBLIC int arch_do_vmctl(m_ptr, p) +register message *m_ptr; /* pointer to request message */ +struct proc *p; +{ + switch(m_ptr->SVMCTL_PARAM) { + case VMCTL_I386_GETCR3: + /* Get process CR3. */ + m_ptr->SVMCTL_VALUE = p->p_seg.p_cr3; + return OK; + case VMCTL_I386_SETCR3: + /* Set process CR3. */ + if(m_ptr->SVMCTL_VALUE) { + p->p_seg.p_cr3 = m_ptr->SVMCTL_VALUE; + p->p_misc_flags |= MF_FULLVM; + } else { + p->p_seg.p_cr3 = kernel_cr3; + p->p_misc_flags &= ~MF_FULLVM; + } + RTS_LOCK_UNSET(p, VMINHIBIT); + return OK; + case VMCTL_GET_PAGEFAULT: + { + struct proc *rp; + if(!(rp=pagefaults)) + return ESRCH; + pagefaults = rp->p_nextpagefault; + if(!RTS_ISSET(rp, PAGEFAULT)) + minix_panic("non-PAGEFAULT process on pagefault chain", + rp->p_endpoint); + m_ptr->SVMCTL_PF_WHO = rp->p_endpoint; + m_ptr->SVMCTL_PF_I386_CR2 = rp->p_pagefault.pf_virtual; + m_ptr->SVMCTL_PF_I386_ERR = rp->p_pagefault.pf_flags; + return OK; + } + } + + kprintf("arch_do_vmctl: strange param %d\n", m_ptr->SVMCTL_PARAM); + return EINVAL; +} diff --git a/kernel/arch/i386/do_int86.c b/kernel/arch/i386/do_int86.c index 9809dc291..9ff1db876 100644 --- a/kernel/arch/i386/do_int86.c +++ b/kernel/arch/i386/do_int86.c @@ -21,28 +21,23 @@ struct reg86u reg86; PUBLIC int do_int86(m_ptr) register message *m_ptr; /* pointer to request message */ { - vir_bytes caller_vir; - phys_bytes caller_phys, kernel_phys; - - caller_vir = (vir_bytes) m_ptr->INT86_REG86; - caller_phys = umap_local(proc_addr(who_p), D, caller_vir, sizeof(reg86)); - if (0 == caller_phys) return(EFAULT); - kernel_phys = vir2phys(®86); - phys_copy(caller_phys, kernel_phys, (phys_bytes) sizeof(reg86)); + data_copy(who_e, (vir_bytes) m_ptr->INT86_REG86, + SYSTEM, (vir_bytes) ®86, sizeof(reg86)); level0(int86); /* Copy results back to the caller */ - phys_copy(kernel_phys, caller_phys, (phys_bytes) sizeof(reg86)); + data_copy(SYSTEM, (vir_bytes) ®86, + who_e, (vir_bytes) m_ptr->INT86_REG86, sizeof(reg86)); /* The BIOS call eats interrupts. Call get_randomness to generate some * entropy. Normally, get_randomness is called from an interrupt handler. * Figuring out the exact source is too complicated. CLOCK_IRQ is normally * not very random. */ - lock(0, "do_int86"); + lock; get_randomness(CLOCK_IRQ); - unlock(0); + unlock; return(OK); } diff --git a/kernel/arch/i386/do_readbios.c b/kernel/arch/i386/do_readbios.c index d09602f4c..d5a5a068c 100644 --- a/kernel/arch/i386/do_readbios.c +++ b/kernel/arch/i386/do_readbios.c @@ -16,24 +16,14 @@ PUBLIC int do_readbios(m_ptr) register message *m_ptr; /* pointer to request message */ { - int proc_nr; - struct proc *p; - phys_bytes address, phys_buf, phys_bios; - vir_bytes buf; - size_t size; + struct vir_addr src, dst; + + src.segment = BIOS_SEG; + dst.segment = D; + src.offset = m_ptr->RDB_ADDR; + dst.offset = (vir_bytes) m_ptr->RDB_BUF; + src.proc_nr_e = NONE; + dst.proc_nr_e = m_ptr->m_source; - address = m_ptr->RDB_ADDR; - buf = (vir_bytes)m_ptr->RDB_BUF; - size = m_ptr->RDB_SIZE; - - okendpt(m_ptr->m_source, &proc_nr); - p = proc_addr(proc_nr); - phys_buf = umap_local(p, D, buf, size); - if (phys_buf == 0) - return EFAULT; - phys_bios = umap_bios(p, address, size); - if (phys_bios == 0) - return EPERM; - phys_copy(phys_bios, phys_buf, size); - return 0; + return virtual_copy_vmcheck(&src, &dst, m_ptr->RDB_SIZE); } diff --git a/kernel/arch/i386/do_sdevio.c b/kernel/arch/i386/do_sdevio.c index c0ea693d7..5028d9e65 100644 --- a/kernel/arch/i386/do_sdevio.c +++ b/kernel/arch/i386/do_sdevio.c @@ -77,7 +77,7 @@ register message *m_ptr; /* pointer to request message */ return EPERM; } /* Get and check physical address. */ - if ((phys_buf = numap_local(proc_nr, + if ((phys_buf = umap_virtual(proc_addr(proc_nr), D, (vir_bytes) m_ptr->DIO_VEC_ADDR, count)) == 0) return(EFAULT); } diff --git a/kernel/arch/i386/exception.c b/kernel/arch/i386/exception.c index a979fe877..7fa7cc686 100755 --- a/kernel/arch/i386/exception.c +++ b/kernel/arch/i386/exception.c @@ -6,8 +6,66 @@ #include "../../kernel.h" #include "proto.h" #include +#include +#include +#include #include "../../proc.h" +extern int vm_copy_in_progress; +extern struct proc *vm_copy_from, *vm_copy_to; +extern u32_t vm_copy_from_v, vm_copy_to_v; +extern u32_t vm_copy_from_p, vm_copy_to_p, vm_copy_cr3; + +u32_t pagefault_cr2, pagefault_count = 0; + +void pagefault(struct proc *pr, int trap_errno) +{ + int s; + vir_bytes ph; + u32_t pte; + + if(pagefault_count != 1) + minix_panic("recursive pagefault", pagefault_count); + + /* Don't schedule this process until pagefault is handled. */ + if(RTS_ISSET(pr, PAGEFAULT)) + minix_panic("PAGEFAULT set", pr->p_endpoint); + RTS_LOCK_SET(pr, PAGEFAULT); + + if(pr->p_endpoint <= INIT_PROC_NR) { + /* Page fault we can't / don't want to + * handle. + */ + kprintf("pagefault for process %d ('%s'), pc = 0x%x\n", + pr->p_endpoint, pr->p_name, pr->p_reg.pc); + proc_stacktrace(pr); + minix_panic("page fault in system process", pr->p_endpoint); + + return; + } + + /* Save pagefault details, suspend process, + * add process to pagefault chain, + * and tell VM there is a pagefault to be + * handled. + */ + pr->p_pagefault.pf_virtual = pagefault_cr2; + pr->p_pagefault.pf_flags = trap_errno; + pr->p_nextpagefault = pagefaults; + pagefaults = pr; + lock_notify(HARDWARE, VM_PROC_NR); + + pagefault_count = 0; + +#if 0 + kprintf("pagefault for process %d ('%s'), pc = 0x%x\n", + pr->p_endpoint, pr->p_name, pr->p_reg.pc); + proc_stacktrace(pr); +#endif + + return; +} + /*===========================================================================* * exception * *===========================================================================*/ @@ -62,8 +120,13 @@ u32_t old_eflags; * k_reenter larger than zero. */ if (k_reenter == 0 && ! iskernelp(saved_proc)) { -#if 0 { + switch(vec_nr) { + case PAGE_FAULT_VECTOR: + pagefault(saved_proc, trap_errno); + return; + } + kprintf( "exception for process %d, endpoint %d ('%s'), pc = 0x%x:0x%x, sp = 0x%x:0x%x\n", proc_nr(saved_proc), saved_proc->p_endpoint, @@ -75,12 +138,11 @@ u32_t old_eflags; vec_nr, (unsigned long)trap_errno, (unsigned long)old_eip, old_cs, (unsigned long)old_eflags); -#if DEBUG_STACKTRACE - stacktrace(saved_proc); -#endif + proc_stacktrace(saved_proc); } -#endif + kprintf("kernel: cause_sig %d for %d\n", + ep->signum, saved_proc->p_endpoint); cause_sig(proc_nr(saved_proc), ep->signum); return; } @@ -92,43 +154,45 @@ u32_t old_eflags; kprintf("\n%s\n", ep->msg); kprintf("k_reenter = %d ", k_reenter); kprintf("process %d (%s), ", proc_nr(saved_proc), saved_proc->p_name); - kprintf("pc = %u:0x%x", (unsigned) saved_proc->p_reg.cs, - (unsigned) saved_proc->p_reg.pc); + kprintf("pc = %u:0x%x\n", (unsigned) saved_proc->p_reg.cs, + (unsigned) saved_proc->p_reg.pc); kprintf( "vec_nr= %d, trap_errno= 0x%lx, eip= 0x%lx, cs= 0x%x, eflags= 0x%lx\n", vec_nr, (unsigned long)trap_errno, (unsigned long)old_eip, old_cs, (unsigned long)old_eflags); + proc_stacktrace(saved_proc); - panic("exception in a kernel task", NO_NUM); + minix_panic("exception in a kernel task", saved_proc->p_endpoint); } -#if DEBUG_STACKTRACE /*===========================================================================* * stacktrace * *===========================================================================*/ -PUBLIC void stacktrace(struct proc *proc) +PUBLIC void proc_stacktrace(struct proc *proc) { reg_t bp, v_bp, v_pc, v_hbp; v_bp = proc->p_reg.fp; - kprintf("stacktrace: "); + kprintf("ep %d pc 0x%lx stack ", proc->p_endpoint, proc->p_reg.pc); + while(v_bp) { - phys_bytes p; - if(!(p = umap_local(proc, D, v_bp, sizeof(v_bp)))) { - kprintf("(bad bp %lx)", v_bp); + if(data_copy(proc->p_endpoint, v_bp, + SYSTEM, (vir_bytes) &v_hbp, sizeof(v_hbp)) != OK) { + kprintf("(v_bp 0x%lx ?)", v_bp); + break; + } + if(data_copy(proc->p_endpoint, v_bp + sizeof(v_pc), + SYSTEM, (vir_bytes) &v_pc, sizeof(v_pc)) != OK) { + kprintf("(v_pc 0x%lx ?)", v_pc); break; } - phys_copy(p+sizeof(v_pc), vir2phys(&v_pc), sizeof(v_pc)); - phys_copy(p, vir2phys(&v_hbp), sizeof(v_hbp)); kprintf("0x%lx ", (unsigned long) v_pc); if(v_hbp != 0 && v_hbp <= v_bp) { - kprintf("(bad hbp %lx)", v_hbp); + kprintf("(hbp %lx ?)", v_hbp); break; } v_bp = v_hbp; } kprintf("\n"); } -#endif - diff --git a/kernel/arch/i386/include/archconst.h b/kernel/arch/i386/include/archconst.h index 2340a830f..d1d78d5f2 100644 --- a/kernel/arch/i386/include/archconst.h +++ b/kernel/arch/i386/include/archconst.h @@ -135,12 +135,6 @@ #define IF_MASK 0x00000200 #define IOPL_MASK 0x003000 -/* Sizes of memory tables. The boot monitor distinguishes three memory areas, - * namely low mem below 1M, 1M-16M, and mem after 16M. More chunks are needed - * for DOS MINIX. - */ -#define NR_MEMS 8 - #define vir2phys(vir) (kinfo.data_base + (vir_bytes) (vir)) #endif /* _I386_ACONST_H */ diff --git a/kernel/arch/i386/include/archtypes.h b/kernel/arch/i386/include/archtypes.h index a506a18b3..ac17eeb7f 100644 --- a/kernel/arch/i386/include/archtypes.h +++ b/kernel/arch/i386/include/archtypes.h @@ -55,8 +55,18 @@ struct segdesc_s { /* segment descriptor for protected mode */ typedef struct segframe { reg_t p_ldt_sel; /* selector in gdt with ldt base and limit */ + reg_t p_cr3; /* page table root */ struct segdesc_s p_ldt[2+NR_REMOTE_SEGS]; /* CS, DS and remote */ } segframe_t; +/* Page fault event. Stored in process table. Only valid if PAGEFAULT + * set in p_rts_flags. + */ +struct pagefault +{ + u32_t pf_virtual; /* Address causing fault (CR2). */ + u32_t pf_flags; /* Pagefault flags on stack. */ +}; + #endif /* #ifndef _I386_TYPES_H */ diff --git a/kernel/arch/i386/klib386.s b/kernel/arch/i386/klib386.s index d978c6f52..e91bba094 100755 --- a/kernel/arch/i386/klib386.s +++ b/kernel/arch/i386/klib386.s @@ -8,6 +8,7 @@ #include #include #include "../../const.h" +#include "vm.h" #include "sconst.h" ! This file contains a number of assembly code utility routines needed by the @@ -15,7 +16,7 @@ .define _monitor ! exit Minix and return to the monitor .define _int86 ! let the monitor make an 8086 interrupt call -.define _cp_mess ! copies messages from source to destination +!.define _cp_mess ! copies messages from source to destination .define _exit ! dummy for library routines .define __exit ! dummy for library routines .define ___exit ! dummy for library routines @@ -34,8 +35,11 @@ .define _level0 ! call a function at level 0 .define _read_cpu_flags ! read the cpu flags .define _read_cr0 ! read cr0 +.define _write_cr3 ! write cr3 +.define _last_cr3 .define _write_cr0 ! write a value in cr0 -.define _write_cr3 ! write a value in cr3 (root of the page table) + +.define _kernel_cr3 ! The routines only guarantee to preserve the registers the C compiler ! expects to be preserved (ebx, esi, edi, ebp, esp, segment registers, and @@ -162,42 +166,42 @@ csinit: mov eax, DS_SELECTOR ! Note that the message size, "Msize" is in DWORDS (not bytes) and must be set ! correctly. Changing the definition of message in the type file and not ! changing it here will lead to total disaster. - -CM_ARGS = 4 + 4 + 4 + 4 + 4 ! 4 + 4 + 4 + 4 + 4 -! es ds edi esi eip proc scl sof dcl dof - - .align 16 -_cp_mess: - cld - push esi - push edi - push ds - push es - - mov eax, FLAT_DS_SELECTOR - mov ds, ax - mov es, ax - - mov esi, CM_ARGS+4(esp) ! src clicks - shl esi, CLICK_SHIFT - add esi, CM_ARGS+4+4(esp) ! src offset - mov edi, CM_ARGS+4+4+4(esp) ! dst clicks - shl edi, CLICK_SHIFT - add edi, CM_ARGS+4+4+4+4(esp) ! dst offset - - mov eax, CM_ARGS(esp) ! process number of sender - stos ! copy number of sender to dest message - add esi, 4 ! do not copy first word - mov ecx, Msize - 1 ! remember, first word does not count - rep - movs ! copy the message - - pop es - pop ds - pop edi - pop esi - ret ! that is all folks! - +! +!CM_ARGS = 4 + 4 + 4 + 4 + 4 ! 4 + 4 + 4 + 4 + 4 +!! es ds edi esi eip proc scl sof dcl dof +! +! .align 16 +!_cp_mess: +! cld +! push esi +! push edi +! push ds +! push es +! +! mov eax, FLAT_DS_SELECTOR +! mov ds, ax +! mov es, ax +! +! mov esi, CM_ARGS+4(esp) ! src clicks +! shl esi, CLICK_SHIFT +! add esi, CM_ARGS+4+4(esp) ! src offset +! mov edi, CM_ARGS+4+4+4(esp) ! dst clicks +! shl edi, CLICK_SHIFT +! add edi, CM_ARGS+4+4+4+4(esp) ! dst offset +! +! mov eax, CM_ARGS(esp) ! process number of sender +! stos ! copy number of sender to dest message +! add esi, 4 ! do not copy first word +! mov ecx, Msize - 1 ! remember, first word does not count +! rep +! movs ! copy the message +! +! pop es +! pop ds +! pop edi +! pop esi +! ret ! that is all folks! +! !*===========================================================================* !* exit * @@ -229,6 +233,9 @@ _phys_insw: cld push edi push es + + LOADKERNELCR3 + mov ecx, FLAT_DS_SELECTOR mov es, cx mov edx, 8(ebp) ! port to read from @@ -254,6 +261,9 @@ _phys_insb: cld push edi push es + + LOADKERNELCR3 + mov ecx, FLAT_DS_SELECTOR mov es, cx mov edx, 8(ebp) ! port to read from @@ -280,6 +290,9 @@ _phys_outsw: cld push esi push ds + + LOADKERNELCR3 + mov ecx, FLAT_DS_SELECTOR mov ds, cx mov edx, 8(ebp) ! port to write to @@ -306,6 +319,9 @@ _phys_outsb: cld push esi push ds + + LOADKERNELCR3 + mov ecx, FLAT_DS_SELECTOR mov ds, cx mov edx, 8(ebp) ! port to write to @@ -412,6 +428,8 @@ _phys_copy: push edi push es + LOADKERNELCR3 + mov eax, FLAT_DS_SELECTOR mov es, ax @@ -456,6 +474,9 @@ _phys_memset: push esi push ebx push ds + + LOADKERNELCR3 + mov esi, 8(ebp) mov eax, 16(ebp) mov ebx, FLAT_DS_SELECTOR @@ -485,6 +506,7 @@ fill_done: pop esi pop ebp ret + !*===========================================================================* !* mem_rdw * @@ -585,14 +607,13 @@ _write_cr0: ret !*===========================================================================* -!* write_cr3 * +!* write_cr3 * !*===========================================================================* ! PUBLIC void write_cr3(unsigned long value); _write_cr3: - push ebp - mov ebp, esp - mov eax, 8(ebp) - mov cr3, eax - pop ebp + push ebp + mov ebp, esp + LOADCR3WITHEAX(0x22, 8(ebp)) + pop ebp ret diff --git a/kernel/arch/i386/memory.c b/kernel/arch/i386/memory.c index 53a2aea38..e02008868 100644 --- a/kernel/arch/i386/memory.c +++ b/kernel/arch/i386/memory.c @@ -1,20 +1,26 @@ #include "../../kernel.h" #include "../../proc.h" +#include "../../vm.h" #include +#include +#include #include -#include +#include #include #include "proto.h" +#include "../../proto.h" +#include "../../debug.h" /* VM functions and data. */ - -PRIVATE int vm_needs_init= 1; PRIVATE u32_t vm_cr3; +PUBLIC u32_t kernel_cr3; +extern u32_t cswitch; +u32_t last_cr3 = 0; FORWARD _PROTOTYPE( void phys_put32, (phys_bytes addr, u32_t value) ); FORWARD _PROTOTYPE( u32_t phys_get32, (phys_bytes addr) ); @@ -22,6 +28,13 @@ FORWARD _PROTOTYPE( void vm_set_cr3, (u32_t value) ); FORWARD _PROTOTYPE( void set_cr3, (void) ); FORWARD _PROTOTYPE( void vm_enable_paging, (void) ); +#if DEBUG_VMASSERT +#define vmassert(t) { \ + if(!(t)) { minix_panic("vm: assert " #t " failed\n", __LINE__); } } +#else +#define vmassert(t) { } +#endif + /* *** Internal VM Functions *** */ PUBLIC void vm_init(void) @@ -31,31 +44,35 @@ PUBLIC void vm_init(void) phys_bytes vm_dir_base, vm_pt_base, phys_mem; u32_t entry; unsigned pages; + struct proc* rp; if (!vm_size) - panic("i386_vm_init: no space for page tables", NO_NUM); + minix_panic("i386_vm_init: no space for page tables", NO_NUM); + + if(vm_running) + return; /* Align page directory */ - o= (vm_base % PAGE_SIZE); + o= (vm_base % I386_PAGE_SIZE); if (o != 0) - o= PAGE_SIZE-o; + o= I386_PAGE_SIZE-o; vm_dir_base= vm_base+o; /* Page tables start after the page directory */ - vm_pt_base= vm_dir_base+PAGE_SIZE; + vm_pt_base= vm_dir_base+I386_PAGE_SIZE; pt_size= (vm_base+vm_size)-vm_pt_base; - pt_size -= (pt_size % PAGE_SIZE); + pt_size -= (pt_size % I386_PAGE_SIZE); /* Compute the number of pages based on vm_mem_high */ - pages= (vm_mem_high-1)/PAGE_SIZE + 1; + pages= (vm_mem_high-1)/I386_PAGE_SIZE + 1; if (pages * I386_VM_PT_ENT_SIZE > pt_size) - panic("i386_vm_init: page table too small", NO_NUM); + minix_panic("i386_vm_init: page table too small", NO_NUM); for (p= 0; p*I386_VM_PT_ENT_SIZE < pt_size; p++) { - phys_mem= p*PAGE_SIZE; + phys_mem= p*I386_PAGE_SIZE; entry= phys_mem | I386_VM_USER | I386_VM_WRITE | I386_VM_PRESENT; if (phys_mem >= vm_mem_high) @@ -65,15 +82,33 @@ PUBLIC void vm_init(void) for (p= 0; p < I386_VM_DIR_ENTRIES; p++) { - phys_mem= vm_pt_base + p*PAGE_SIZE; + phys_mem= vm_pt_base + p*I386_PAGE_SIZE; entry= phys_mem | I386_VM_USER | I386_VM_WRITE | I386_VM_PRESENT; if (phys_mem >= vm_pt_base + pt_size) entry= 0; phys_put32(vm_dir_base + p*I386_VM_PT_ENT_SIZE, entry); } + + /* Set this cr3 in all currently running processes for + * future context switches. + */ + for (rp=BEG_PROC_ADDR; rpp_seg.p_cr3 = vm_dir_base; + } + + kernel_cr3 = vm_dir_base; + + /* Set this cr3 now (not active until paging enabled). */ vm_set_cr3(vm_dir_base); + + /* Actually enable paging (activating cr3 load above). */ level0(vm_enable_paging); + + /* Don't do this init in the future. */ + vm_running = 1; } PRIVATE void phys_put32(addr, value) @@ -113,50 +148,6 @@ PRIVATE void vm_enable_paging(void) write_cr0(cr0 | I386_CR0_PG); } -PUBLIC void vm_map_range(base, size, offset) -u32_t base; -u32_t size; -u32_t offset; -{ - u32_t curr_pt, curr_pt_addr, entry; - int dir_ent, pt_ent; - - if (base % PAGE_SIZE != 0) - panic("map_range: bad base", base); - if (size % PAGE_SIZE != 0) - panic("map_range: bad size", size); - if (offset % PAGE_SIZE != 0) - panic("map_range: bad offset", offset); - - curr_pt= -1; - curr_pt_addr= 0; - while (size != 0) - { - dir_ent= (base >> I386_VM_DIR_ENT_SHIFT); - pt_ent= (base >> I386_VM_PT_ENT_SHIFT) & I386_VM_PT_ENT_MASK; - if (dir_ent != curr_pt) - { - /* Get address of page table */ - curr_pt= dir_ent; - curr_pt_addr= phys_get32(vm_cr3 + - dir_ent * I386_VM_PT_ENT_SIZE); - curr_pt_addr &= I386_VM_ADDR_MASK; - } - entry= offset | I386_VM_USER | I386_VM_WRITE | - I386_VM_PRESENT; -#if 0 /* Do we need this for memory mapped I/O? */ - entry |= I386_VM_PCD | I386_VM_PWT; -#endif - phys_put32(curr_pt_addr + pt_ent * I386_VM_PT_ENT_SIZE, entry); - offset += PAGE_SIZE; - base += PAGE_SIZE; - size -= PAGE_SIZE; - } - - /* reload root of page table. */ - vm_set_cr3(vm_cr3); -} - PUBLIC vir_bytes alloc_remote_segment(u32_t *selector, segframe_t *segments, int index, phys_bytes phys, vir_bytes size, int priv) @@ -188,6 +179,10 @@ PUBLIC phys_bytes umap_remote(struct proc* rp, int seg, /* Calculate the physical memory address for a given virtual address. */ struct far_mem *fm; +#if 0 + if(rp->p_misc_flags & MF_FULLVM) return 0; +#endif + if (bytes <= 0) return( (phys_bytes) 0); if (seg < 0 || seg >= NR_REMOTE_SEGS) return( (phys_bytes) 0); @@ -212,6 +207,9 @@ vir_bytes bytes; /* # of bytes to be copied */ phys_bytes pa; /* intermediate variables as phys_bytes */ phys_bytes seg_base; + if(seg != T && seg != D && seg != S) + minix_panic("umap_local: wrong seg", seg); + if (bytes <= 0) return( (phys_bytes) 0); if (vir_addr + bytes <= vir_addr) return 0; /* overflow */ vc = (vir_addr + bytes - 1) >> CLICK_SHIFT; /* last click of data */ @@ -232,3 +230,569 @@ vir_bytes bytes; /* # of bytes to be copied */ return(seg_base + pa); } +/*===========================================================================* + * umap_virtual * + *===========================================================================*/ +PUBLIC phys_bytes umap_virtual(rp, seg, vir_addr, bytes) +register struct proc *rp; /* pointer to proc table entry for process */ +int seg; /* T, D, or S segment */ +vir_bytes vir_addr; /* virtual address in bytes within the seg */ +vir_bytes bytes; /* # of bytes to be copied */ +{ + vir_bytes linear; + u32_t phys = 0; + + if(seg == MEM_GRANT) { + phys = umap_grant(rp, vir_addr, bytes); + } else { + if(!(linear = umap_local(rp, seg, vir_addr, bytes))) { + kprintf("SYSTEM:umap_virtual: umap_local failed\n"); + phys = 0; + } else { + if(vm_lookup(rp, linear, &phys, NULL) != OK) { + kprintf("SYSTEM:umap_virtual: vm_lookup of %s: seg 0x%lx: 0x%lx failed\n", rp->p_name, seg, vir_addr); + phys = 0; + } + if(phys == 0) + minix_panic("vm_lookup returned phys", phys); + } + } + + if(phys == 0) { + kprintf("SYSTEM:umap_virtual: lookup failed\n"); + return 0; + } + + /* Now make sure addresses are contiguous in physical memory + * so that the umap makes sense. + */ + if(bytes > 0 && !vm_contiguous(rp, linear, bytes)) { + kprintf("umap_virtual: %s: %d at 0x%lx (vir 0x%lx) not contiguous\n", + rp->p_name, bytes, linear, vir_addr); + return 0; + } + + /* phys must be larger than 0 (or the caller will think the call + * failed), and address must not cross a page boundary. + */ + vmassert(phys); + + return phys; +} + +/*===========================================================================* + * vm_lookup * + *===========================================================================*/ +PUBLIC int vm_lookup(struct proc *proc, vir_bytes virtual, vir_bytes *physical, u32_t *ptent) +{ + u32_t *root, *pt; + int pde, pte; + u32_t pde_v, pte_v; + + vmassert(proc); + vmassert(physical); + vmassert(!(proc->p_rts_flags & SLOT_FREE)); + + /* Retrieve page directory entry. */ + root = (u32_t *) proc->p_seg.p_cr3; + vmassert(!((u32_t) root % I386_PAGE_SIZE)); + pde = I386_VM_PDE(virtual); + vmassert(pde >= 0 && pde < I386_VM_DIR_ENTRIES); + pde_v = phys_get32((u32_t) (root + pde)); + if(!(pde_v & I386_VM_PRESENT)) { +#if 0 + kprintf("vm_lookup: %d:%s:0x%lx: cr3 0x%lx: pde %d not present\n", + proc->p_endpoint, proc->p_name, virtual, root, pde); + kprintf("kernel stack: "); + util_stacktrace(); +#endif + return EFAULT; + } + + /* Retrieve page table entry. */ + pt = (u32_t *) I386_VM_PFA(pde_v); + vmassert(!((u32_t) pt % I386_PAGE_SIZE)); + pte = I386_VM_PTE(virtual); + vmassert(pte >= 0 && pte < I386_VM_PT_ENTRIES); + pte_v = phys_get32((u32_t) (pt + pte)); + if(!(pte_v & I386_VM_PRESENT)) { +#if 0 + kprintf("vm_lookup: %d:%s:0x%lx: cr3 %lx: pde %d: pte %d not present\n", + proc->p_endpoint, proc->p_name, virtual, root, pde, pte); + kprintf("kernel stack: "); + util_stacktrace(); +#endif + return EFAULT; + } + + if(ptent) *ptent = pte_v; + + /* Actual address now known; retrieve it and add page offset. */ + *physical = I386_VM_PFA(pte_v); + *physical += virtual % I386_PAGE_SIZE; + + return OK; +} + +/* From virtual address v in process p, + * lookup physical address and assign it to d. + * If p is NULL, assume it's already a physical address. + */ +#define LOOKUP(d, p, v, flagsp) { \ + int r; \ + if(!(p)) { (d) = (v); } \ + else { \ + if((r=vm_lookup((p), (v), &(d), flagsp)) != OK) { \ + kprintf("vm_copy: lookup failed of 0x%lx in %d (%s)\n"\ + "kernel stacktrace: ", (v), (p)->p_endpoint, \ + (p)->p_name); \ + util_stacktrace(); \ + return r; \ + } } } + +/*===========================================================================* + * vm_copy * + *===========================================================================*/ +int vm_copy(vir_bytes src, struct proc *srcproc, + vir_bytes dst, struct proc *dstproc, phys_bytes bytes) +{ +#define WRAPS(v) (ULONG_MAX - (v) <= bytes) + + if(WRAPS(src) || WRAPS(dst)) + minix_panic("vm_copy: linear address wraps", NO_NUM); + + while(bytes > 0) { + u32_t n, flags; + phys_bytes p_src, p_dst; +#define PAGEREMAIN(v) (I386_PAGE_SIZE - ((v) % I386_PAGE_SIZE)) + + /* We can copy this number of bytes without + * crossing a page boundary, but don't copy more + * than asked. + */ + n = MIN(PAGEREMAIN(src), PAGEREMAIN(dst)); + n = MIN(n, bytes); + vmassert(n > 0); + vmassert(n <= I386_PAGE_SIZE); + + /* Convert both virtual addresses to physical and do + * copy. + */ + LOOKUP(p_src, srcproc, src, NULL); + LOOKUP(p_dst, dstproc, dst, &flags); + if(!(flags & I386_VM_WRITE)) { + kprintf("vm_copy: copying to nonwritable page\n"); + kprintf("kernel stack: "); + util_stacktrace(); + return EFAULT; + } + phys_copy(p_src, p_dst, n); + + /* Book number of bytes copied. */ + vmassert(bytes >= n); + bytes -= n; + src += n; + dst += n; + } + + return OK; +} + +/*===========================================================================* + * vm_contiguous * + *===========================================================================*/ +PUBLIC int vm_contiguous(struct proc *targetproc, u32_t vir_buf, size_t bytes) +{ + int first = 1, r, boundaries = 0; + u32_t prev_phys, po; + u32_t prev_vir; + + vmassert(targetproc); + vmassert(bytes > 0); + vmassert(vm_running); + + /* Start and end at page boundary to make logic simpler. */ + po = vir_buf % I386_PAGE_SIZE; + if(po > 0) { + bytes += po; + vir_buf -= po; + } + po = (vir_buf + bytes) % I386_PAGE_SIZE; + if(po > 0) + bytes += I386_PAGE_SIZE - po; + + /* Keep going as long as we cross a page boundary. */ + while(bytes > 0) { + u32_t phys; + + if((r=vm_lookup(targetproc, vir_buf, &phys, NULL)) != OK) { + kprintf("vm_contiguous: vm_lookup failed, %d\n", r); + kprintf("kernel stack: "); + util_stacktrace(); + return 0; + } + + if(!first) { + if(prev_phys+I386_PAGE_SIZE != phys) { + kprintf("vm_contiguous: no (0x%lx, 0x%lx)\n", + prev_phys, phys); + kprintf("kernel stack: "); + util_stacktrace(); + return 0; + } + } + + first = 0; + + prev_phys = phys; + prev_vir = vir_buf; + vir_buf += I386_PAGE_SIZE; + bytes -= I386_PAGE_SIZE; + boundaries++; + } + + if(verbose_vm) + kprintf("vm_contiguous: yes (%d boundaries tested)\n", + boundaries); + + return 1; +} + +int vm_checkrange_verbose = 0; + +/*===========================================================================* + * vm_checkrange * + *===========================================================================*/ +PUBLIC int vm_checkrange(struct proc *caller, struct proc *target, + vir_bytes vir, vir_bytes bytes, int wrfl, int checkonly) +{ + u32_t flags, po, v; + int r; + + vmassert(vm_running); + + /* If caller has had a reply to this request, return it. */ + if(RTS_ISSET(caller, VMREQUEST)) { + if(caller->p_vmrequest.who == target->p_endpoint) { + if(caller->p_vmrequest.vmresult == VMSUSPEND) + minix_panic("check sees VMSUSPEND?", NO_NUM); + RTS_LOCK_UNSET(caller, VMREQUEST); +#if 0 + kprintf("SYSTEM: vm_checkrange: returning vmresult %d\n", + caller->p_vmrequest.vmresult); +#endif + return caller->p_vmrequest.vmresult; + } else { +#if 0 + kprintf("SYSTEM: vm_checkrange: caller has a request for %d, " + "but our target is %d\n", + caller->p_vmrequest.who, target->p_endpoint); +#endif + } + } + + po = vir % I386_PAGE_SIZE; + if(po > 0) { + vir -= po; + bytes += po; + } + + vmassert(target); + vmassert(bytes > 0); + + for(v = vir; v < vir + bytes; v+= I386_PAGE_SIZE) { + u32_t phys; + + /* If page exists and it's writable if desired, we're OK + * for this page. + */ + if(vm_lookup(target, v, &phys, &flags) == OK && + !(wrfl && !(flags & I386_VM_WRITE))) { + if(vm_checkrange_verbose) { +#if 0 + kprintf("SYSTEM: checkrange:%s:%d: 0x%lx: write 0x%lx, flags 0x%lx, phys 0x%lx, OK\n", + target->p_name, target->p_endpoint, v, wrfl, flags, phys); +#endif + } + continue; + } + + if(vm_checkrange_verbose) { + kprintf("SYSTEM: checkrange:%s:%d: 0x%lx: write 0x%lx, flags 0x%lx, phys 0x%lx, NOT OK\n", + target->p_name, target->p_endpoint, v, wrfl, flags, phys); + } + + if(checkonly) + return VMSUSPEND; + + /* This range is not OK for this process. Set parameters + * of the request and notify VM about the pending request. + */ + if(RTS_ISSET(caller, VMREQUEST)) + minix_panic("VMREQUEST already set", caller->p_endpoint); + RTS_LOCK_SET(caller, VMREQUEST); + + /* Set parameters in caller. */ + caller->p_vmrequest.writeflag = wrfl; + caller->p_vmrequest.start = vir; + caller->p_vmrequest.length = bytes; + caller->p_vmrequest.who = target->p_endpoint; + + /* Set caller in target. */ + target->p_vmrequest.requestor = caller; + + /* Connect caller on vmrequest wait queue. */ + caller->p_vmrequest.nextrequestor = vmrequest; + vmrequest = caller; + soft_notify(VM_PROC_NR); + +#if 0 + kprintf("SYSTEM: vm_checkrange: range bad for " + "target %s:0x%lx-0x%lx, caller %s\n", + target->p_name, vir, vir+bytes, caller->p_name); + + kprintf("vm_checkrange kernel trace: "); + util_stacktrace(); + kprintf("target trace: "); + proc_stacktrace(target); +#endif + + if(target->p_endpoint == VM_PROC_NR) { + kprintf("caller trace: "); + proc_stacktrace(caller); + kprintf("target trace: "); + proc_stacktrace(target); + minix_panic("VM ranges should be OK", NO_NUM); + } + + return VMSUSPEND; + } + + return OK; +} + +char *flagstr(u32_t e, int dir) +{ + static char str[80]; + strcpy(str, ""); +#define FLAG(v) do { if(e & (v)) { strcat(str, #v " "); } } while(0) + FLAG(I386_VM_PRESENT); + FLAG(I386_VM_WRITE); + FLAG(I386_VM_USER); + FLAG(I386_VM_PWT); + FLAG(I386_VM_PCD); + if(dir) + FLAG(I386_VM_BIGPAGE); /* Page directory entry only */ + else + FLAG(I386_VM_DIRTY); /* Page table entry only */ + + return str; +} + +void vm_pt_print(u32_t *pagetable, u32_t v) +{ + int pte, l = 0; + int col = 0; + + vmassert(!((u32_t) pagetable % I386_PAGE_SIZE)); + + for(pte = 0; pte < I386_VM_PT_ENTRIES; pte++) { + u32_t pte_v, pfa; + pte_v = phys_get32((u32_t) (pagetable + pte)); + if(!(pte_v & I386_VM_PRESENT)) + continue; + pfa = I386_VM_PFA(pte_v); + kprintf("%4d:%08lx:%08lx ", + pte, v + I386_PAGE_SIZE*pte, pfa); + col++; + if(col == 3) { kprintf("\n"); col = 0; } + } + if(col > 0) kprintf("\n"); + + return; +} + +/*===========================================================================* + * vm_print * + *===========================================================================*/ +void vm_print(u32_t *root) +{ + int pde; + + vmassert(!((u32_t) root % I386_PAGE_SIZE)); + + for(pde = 0; pde < I386_VM_DIR_ENTRIES; pde++) { + u32_t pde_v; + u32_t *pte_a; + pde_v = phys_get32((u32_t) (root + pde)); + if(!(pde_v & I386_VM_PRESENT)) + continue; + pte_a = (u32_t *) I386_VM_PFA(pde_v); + kprintf("%4d: pt %08lx %s\n", + pde, pte_a, flagstr(pde_v, 1)); + vm_pt_print(pte_a, pde * I386_VM_PT_ENTRIES * I386_PAGE_SIZE); + } + + + return; +} + +/*===========================================================================* + * virtual_copy_f * + *===========================================================================*/ +PUBLIC int virtual_copy_f(src_addr, dst_addr, bytes, vmcheck) +struct vir_addr *src_addr; /* source virtual address */ +struct vir_addr *dst_addr; /* destination virtual address */ +vir_bytes bytes; /* # of bytes to copy */ +int vmcheck; /* if nonzero, can return VMSUSPEND */ +{ +/* Copy bytes from virtual address src_addr to virtual address dst_addr. + * Virtual addresses can be in ABS, LOCAL_SEG, REMOTE_SEG, or BIOS_SEG. + */ + struct vir_addr *vir_addr[2]; /* virtual source and destination address */ + phys_bytes phys_addr[2]; /* absolute source and destination */ + int seg_index; + int i, r; + struct proc *procs[2]; + + /* Check copy count. */ + if (bytes <= 0) return(EDOM); + + /* Do some more checks and map virtual addresses to physical addresses. */ + vir_addr[_SRC_] = src_addr; + vir_addr[_DST_] = dst_addr; + + for (i=_SRC_; i<=_DST_; i++) { + int proc_nr, type; + struct proc *p; + + type = vir_addr[i]->segment & SEGMENT_TYPE; + if((type != PHYS_SEG && type != BIOS_SEG) && + isokendpt(vir_addr[i]->proc_nr_e, &proc_nr)) + p = proc_addr(proc_nr); + else + p = NULL; + + procs[i] = p; + + /* Get physical address. */ + switch(type) { + case LOCAL_SEG: + case LOCAL_VM_SEG: + if(!p) return EDEADSRCDST; + seg_index = vir_addr[i]->segment & SEGMENT_INDEX; + if(type == LOCAL_SEG) + phys_addr[i] = umap_local(p, seg_index, vir_addr[i]->offset, + bytes); + else + phys_addr[i] = umap_virtual(p, seg_index, vir_addr[i]->offset, + bytes); + if(phys_addr[i] == 0) { + kprintf("virtual_copy: map 0x%x failed for %s seg %d, " + "offset %lx, len %d, i %d\n", + type, p->p_name, seg_index, vir_addr[i]->offset, + bytes, i); + } + break; + case REMOTE_SEG: + if(!p) return EDEADSRCDST; + seg_index = vir_addr[i]->segment & SEGMENT_INDEX; + phys_addr[i] = umap_remote(p, seg_index, vir_addr[i]->offset, bytes); + break; +#if _MINIX_CHIP == _CHIP_INTEL + case BIOS_SEG: + phys_addr[i] = umap_bios(vir_addr[i]->offset, bytes ); + break; +#endif + case PHYS_SEG: + phys_addr[i] = vir_addr[i]->offset; + break; + case GRANT_SEG: + phys_addr[i] = umap_grant(p, vir_addr[i]->offset, bytes); + break; + default: + kprintf("virtual_copy: strange type 0x%x\n", type); + return(EINVAL); + } + + /* Check if mapping succeeded. */ + if (phys_addr[i] <= 0 && vir_addr[i]->segment != PHYS_SEG) { + kprintf("virtual_copy EFAULT\n"); + return(EFAULT); + } + } + + if(vmcheck && procs[_SRC_]) + CHECKRANGE_OR_SUSPEND(procs[_SRC_], phys_addr[_SRC_], bytes, 0); + if(vmcheck && procs[_DST_]) + CHECKRANGE_OR_SUSPEND(procs[_DST_], phys_addr[_DST_], bytes, 1); + + /* Now copy bytes between physical addresseses. */ + if(!vm_running || (procs[_SRC_] == NULL && procs[_DST_] == NULL)) { + /* Without vm, address ranges actually are physical. */ + phys_copy(phys_addr[_SRC_], phys_addr[_DST_], (phys_bytes) bytes); + r = OK; + } else { + /* With vm, addresses need further interpretation. */ + r = vm_copy(phys_addr[_SRC_], procs[_SRC_], + phys_addr[_DST_], procs[_DST_], (phys_bytes) bytes); + if(r != OK) { + kprintf("vm_copy: %lx to %lx failed\n", + phys_addr[_SRC_],phys_addr[_DST_]); + } + } + + return(r); +} + +/*===========================================================================* + * data_copy * + *===========================================================================*/ +PUBLIC int data_copy( + endpoint_t from_proc, vir_bytes from_addr, + endpoint_t to_proc, vir_bytes to_addr, + size_t bytes) +{ + struct vir_addr src, dst; + + src.segment = dst.segment = D; + src.offset = from_addr; + dst.offset = to_addr; + src.proc_nr_e = from_proc; + dst.proc_nr_e = to_proc; + + return virtual_copy(&src, &dst, bytes); +} + +/*===========================================================================* + * arch_pre_exec * + *===========================================================================*/ +PUBLIC int arch_pre_exec(struct proc *pr, u32_t ip, u32_t sp) +{ +/* wipe extra LDT entries, set program counter, and stack pointer. */ + memset(pr->p_seg.p_ldt + EXTRA_LDT_INDEX, 0, + sizeof(pr->p_seg.p_ldt[0]) * (LDT_SIZE - EXTRA_LDT_INDEX)); + pr->p_reg.pc = ip; + pr->p_reg.sp = sp; +} + +/*===========================================================================* + * arch_umap * + *===========================================================================*/ +PUBLIC int arch_umap(struct proc *pr, vir_bytes offset, vir_bytes count, + int seg, phys_bytes *addr) +{ + switch(seg) { + case BIOS_SEG: + *addr = umap_bios(offset, count); + return OK; + } + + /* This must be EINVAL; the umap fallback function in + * lib/syslib/alloc_util.c depends on it to detect an + * older kernel (as opposed to mapping error). + */ + return EINVAL; +} + + diff --git a/kernel/arch/i386/mpx386.s b/kernel/arch/i386/mpx386.s index c6f94f14d..15a5cd62f 100755 --- a/kernel/arch/i386/mpx386.s +++ b/kernel/arch/i386/mpx386.s @@ -1,4 +1,4 @@ -# +# ! This file, mpx386.s, is included by mpx.s when Minix is compiled for ! 32-bit Intel CPUs. The alternative mpx88.s is compiled for 16-bit CPUs. @@ -58,6 +58,7 @@ begbss: #include #include #include "../../const.h" +#include "vm.h" #include "sconst.h" /* Selected 386 tss offsets. */ @@ -71,6 +72,13 @@ begbss: .define _restart .define save +.define _kernel_cr3 +.define _pagefault_cr2 +.define _pagefault_count + +.define errexception +.define exception1 +.define exception .define _divide_error .define _single_step_exception @@ -88,6 +96,9 @@ begbss: .define _general_protection .define _page_fault .define _copr_error +.define _params_size +.define _params_offset +.define _mon_ds .define _hwint00 ! handlers for hardware interrupts .define _hwint01 @@ -173,6 +184,11 @@ copygdt: mov ss, ax mov esp, k_stktop ! set sp to point to the top of kernel stack +! Save boot parameters into these global variables for i386 code + mov (_params_size), edx + mov (_params_offset), ebx + mov (_mon_ds), SS_SELECTOR + ! Call C startup code to set up a proper environment to run main(). push edx push ebx @@ -216,6 +232,7 @@ csinit: #define hwint_master(irq) \ call save /* save interrupted process state */;\ push (_irq_handlers+4*irq) /* irq_handlers[irq] */;\ + LOADCR3WITHEAX(irq, (_kernel_cr3)) /* switch to kernel page table */;\ call _intr_handle /* intr_handle(irq_handlers[irq]) */;\ pop ecx ;\ cmp (_irq_actids+4*irq), 0 /* interrupt still active? */;\ @@ -267,6 +284,7 @@ _hwint07: ! Interrupt routine for irq 7 (printer) #define hwint_slave(irq) \ call save /* save interrupted process state */;\ push (_irq_handlers+4*irq) /* irq_handlers[irq] */;\ + LOADCR3WITHEAX(irq, (_kernel_cr3)) /* switch to kernel page table */;\ call _intr_handle /* intr_handle(irq_handlers[irq]) */;\ pop ecx ;\ cmp (_irq_actids+4*irq), 0 /* interrupt still active? */;\ @@ -358,6 +376,7 @@ _p_s_call: o16 push es o16 push fs o16 push gs + mov si, ss ! ss is kernel data segment mov ds, si ! load rest of kernel segments mov es, si ! kernel does not use fs, gs @@ -371,6 +390,9 @@ _p_s_call: push ebx ! pointer to user message push eax ! source / destination push ecx ! call number (ipc primitive to use) + +! LOADCR3WITHEAX(0x20, (_kernel_cr3)) + call _sys_call ! sys_call(call_nr, src_dst, m_ptr, bit_map) ! caller is now explicitly in proc_ptr mov AXREG(esi), eax ! sys_call MUST PRESERVE si @@ -391,6 +413,7 @@ _restart: mov (_next_ptr), 0 0: mov esp, (_proc_ptr) ! will assume P_STACKBASE == 0 lldt P_LDT_SEL(esp) ! enable process' segment descriptors + LOADCR3WITHEAX(0x21, P_CR3(esp)) ! switch to process page table lea eax, P_STACKTOP(esp) ! arrange for next interrupt mov (_tss+TSS3_S_SP0), eax ! to save state in process table restart1: @@ -464,6 +487,11 @@ _general_protection: _page_fault: push PAGE_FAULT_VECTOR + push eax + mov eax, cr2 +sseg mov (_pagefault_cr2), eax +sseg inc (_pagefault_count) + pop eax jmp errexception _copr_error: @@ -492,12 +520,16 @@ errexception: sseg pop (trap_errno) exception1: ! Common for all exceptions. push eax ! eax is scratch register + mov eax, 0+4(esp) ! old eip sseg mov (old_eip), eax movzx eax, 4+4(esp) ! old cs sseg mov (old_cs), eax mov eax, 8+4(esp) ! old eflags sseg mov (old_eflags), eax + + LOADCR3WITHEAX(0x24, (_kernel_cr3)) + pop eax call save push (old_eflags) @@ -517,6 +549,15 @@ _level0_call: call save jmp (_level0_func) +!*===========================================================================* +!* load_kernel_cr3 * +!*===========================================================================* +.align 16 +_load_kernel_cr3: + mov eax, (_kernel_cr3) + mov cr3, eax + ret + !*===========================================================================* !* data * !*===========================================================================* @@ -533,3 +574,4 @@ k_stktop: ! top of kernel stack .comm old_eip, 4 .comm old_cs, 4 .comm old_eflags, 4 + diff --git a/kernel/arch/i386/protect.c b/kernel/arch/i386/protect.c index d303ab59b..a360113eb 100755 --- a/kernel/arch/i386/protect.c +++ b/kernel/arch/i386/protect.c @@ -307,7 +307,10 @@ PUBLIC void alloc_segments(register struct proc *rp) code_bytes = data_bytes; /* common I&D, poor protect */ else code_bytes = (phys_bytes) rp->p_memmap[T].mem_len << CLICK_SHIFT; - privilege = (iskernelp(rp)) ? TASK_PRIVILEGE : USER_PRIVILEGE; + if( (iskernelp(rp))) + privilege = TASK_PRIVILEGE; + else + privilege = USER_PRIVILEGE; init_codeseg(&rp->p_seg.p_ldt[CS_LDT_INDEX], (phys_bytes) rp->p_memmap[T].mem_phys << CLICK_SHIFT, code_bytes, privilege); diff --git a/kernel/arch/i386/proto.h b/kernel/arch/i386/proto.h index 0530bf35a..de8de011e 100644 --- a/kernel/arch/i386/proto.h +++ b/kernel/arch/i386/proto.h @@ -44,10 +44,16 @@ _PROTOTYPE( void trp, (void) ); _PROTOTYPE( void s_call, (void) ), _PROTOTYPE( p_s_call, (void) ); _PROTOTYPE( void level0_call, (void) ); +/* memory.c */ +_PROTOTYPE( void vir_insb, (u16_t port, struct proc *proc, u32_t vir, size_t count)); +_PROTOTYPE( void vir_outsb, (u16_t port, struct proc *proc, u32_t vir, size_t count)); +_PROTOTYPE( void vir_insw, (u16_t port, struct proc *proc, u32_t vir, size_t count)); +_PROTOTYPE( void vir_outsw, (u16_t port, struct proc *proc, u32_t vir, size_t count)); + + /* exception.c */ _PROTOTYPE( void exception, (unsigned vec_nr, u32_t trap_errno, u32_t old_eip, U16_t old_cs, u32_t old_eflags) ); -_PROTOTYPE( void stacktrace, (struct proc *proc) ); /* klib386.s */ _PROTOTYPE( void level0, (void (*func)(void)) ); @@ -62,6 +68,7 @@ _PROTOTYPE( void phys_insb, (U16_t port, phys_bytes buf, size_t count) ); _PROTOTYPE( void phys_insw, (U16_t port, phys_bytes buf, size_t count) ); _PROTOTYPE( void phys_outsb, (U16_t port, phys_bytes buf, size_t count) ); _PROTOTYPE( void phys_outsw, (U16_t port, phys_bytes buf, size_t count) ); +_PROTOTYPE( void i386_invlpg, (U32_t addr) ); /* protect.c */ _PROTOTYPE( void prot_init, (void) ); diff --git a/kernel/arch/i386/sconst.h b/kernel/arch/i386/sconst.h index 28e7b0517..34254f03a 100755 --- a/kernel/arch/i386/sconst.h +++ b/kernel/arch/i386/sconst.h @@ -23,5 +23,6 @@ SPREG = PSWREG + W SSREG = SPREG + W P_STACKTOP = SSREG + W P_LDT_SEL = P_STACKTOP -P_LDT = P_LDT_SEL + W +P_CR3 = P_LDT_SEL + W +P_LDT = P_CR3 + W Msize = 9 ! size of a message in 32-bit words diff --git a/kernel/arch/i386/system.c b/kernel/arch/i386/system.c index 6b7e100ca..aa0aef648 100644 --- a/kernel/arch/i386/system.c +++ b/kernel/arch/i386/system.c @@ -3,10 +3,14 @@ #include "../../kernel.h" #include +#include +#include #include #include #include #include +#include +#include #include "proto.h" #include "../../proc.h" @@ -31,7 +35,39 @@ PUBLIC void arch_shutdown(int how) * the program if not already done. */ if (how != RBT_MONITOR) - phys_copy(vir2phys(""), kinfo.params_base, 1); + arch_set_params("", 1); + if(minix_panicing) { + int source, dest; + static char mybuffer[sizeof(params_buffer)]; + char *lead = "echo \\n*** kernel messages:\\n"; + int leadlen = strlen(lead); + strcpy(mybuffer, lead); + +#define DECSOURCE source = (source - 1 + _KMESS_BUF_SIZE) % _KMESS_BUF_SIZE + + dest = sizeof(mybuffer)-1; + mybuffer[dest--] = '\0'; + + source = kmess.km_next; + DECSOURCE; + + while(dest >= leadlen) { + char c = kmess.km_buf[source]; + if(c == '\n') { + mybuffer[dest--] = 'n'; + mybuffer[dest] = '\\'; + } else if(isprint(c) && + c != '\'' && c != '"' && + c != '\\' && c != ';') { + mybuffer[dest] = c; + } else mybuffer[dest] = '|'; + + DECSOURCE; + dest--; + } + + arch_set_params(mybuffer, strlen(mybuffer)+1); + } level0(monitor); } else { /* Reset the system by forcing a processor shutdown. First stop @@ -44,6 +80,17 @@ PUBLIC void arch_shutdown(int how) } } +/* address of a.out headers, set in mpx386.s */ +phys_bytes aout; + +PUBLIC void arch_get_aout_headers(int i, struct exec *h) +{ + /* The bootstrap loader created an array of the a.out headers at + * absolute address 'aout'. Get one element to h. + */ + phys_copy(aout + i * A_MINHDR, vir2phys(h), (phys_bytes) A_MINHDR); +} + PUBLIC void system_init(void) { prot_init(); @@ -122,7 +169,7 @@ PUBLIC void ser_dump_proc() pp->p_priority, pp->p_max_priority, pp->p_user_time, pp->p_sys_time, pp->p_reg.pc); - stacktrace(pp); + proc_stacktrace(pp); } } @@ -219,3 +266,23 @@ PUBLIC void cons_seth(int pos, int n) else cons_setc(pos, 'A'+(n-10)); } + +/* Saved by mpx386.s into these variables. */ +u32_t params_size, params_offset, mon_ds; + +PUBLIC int arch_get_params(char *params, int maxsize) +{ + phys_copy(seg2phys(mon_ds) + params_offset, vir2phys(params), + MIN(maxsize, params_size)); + params[maxsize-1] = '\0'; + return OK; +} + +PUBLIC int arch_set_params(char *params, int size) +{ + if(size > params_size) + return E2BIG; + phys_copy(vir2phys(params), seg2phys(mon_ds) + params_offset, size); + return OK; +} + diff --git a/kernel/arch/i386/vm.h b/kernel/arch/i386/vm.h new file mode 100644 index 000000000..1707ac990 --- /dev/null +++ b/kernel/arch/i386/vm.h @@ -0,0 +1,27 @@ + +.define _load_kernel_cr3 +.define _last_cr3 + +#define LOADKERNELCR3 ;\ + inc (_cr3switch) ;\ + mov eax, (_kernel_cr3) ;\ + cmp (_last_cr3), eax ;\ + jz 9f ;\ + push _load_kernel_cr3 ;\ + call _level0 ;\ + pop eax ;\ + mov eax, (_kernel_cr3) ;\ + mov (_last_cr3), eax ;\ + inc (_cr3reload) ;\ +9: + +#define LOADCR3WITHEAX(type, newcr3) ;\ +sseg inc (_cr3switch) ;\ +sseg mov eax, newcr3 ;\ +sseg cmp (_last_cr3), eax ;\ + jz 8f ;\ + mov cr3, eax ;\ +sseg inc (_cr3reload) ;\ +sseg mov (_last_cr3), eax ;\ +8: + diff --git a/kernel/clock.c b/kernel/clock.c index 16866eb72..80cc4c474 100755 --- a/kernel/clock.c +++ b/kernel/clock.c @@ -75,7 +75,7 @@ PUBLIC void clock_task() result = receive(ANY, &m); if(result != OK) - panic("receive() failed", result); + minix_panic("receive() failed", result); /* Handle the request. Only clock ticks are expected. */ switch (m.m_type) { @@ -181,6 +181,8 @@ irq_hook_t *hook; */ register unsigned ticks; + if(minix_panicing) return; + /* Get number of ticks and update realtime. */ ticks = lost_ticks + 1; lost_ticks = 0; @@ -201,8 +203,10 @@ irq_hook_t *hook; bill_ptr->p_ticks_left -= ticks; } +#if 0 /* Update load average. */ load_update(); +#endif /* Check if do_clocktick() must be called. Done for alarms and scheduling. * Some processes, such as the kernel tasks, cannot be preempted. diff --git a/kernel/config.h b/kernel/config.h index 371dcae35..0fb906db7 100644 --- a/kernel/config.h +++ b/kernel/config.h @@ -49,12 +49,6 @@ */ #define P_NAME_LEN 8 -/* Kernel diagnostics are written to a circular buffer. After each message, - * a system server is notified and a copy of the buffer can be retrieved to - * display the message. The buffers size can safely be reduced. - */ -#define KMESS_BUF_SIZE 256 - /* Buffer to gather randomness. This is used to generate a random stream by * the MEMORY driver when reading from /dev/random. */ @@ -74,11 +68,5 @@ #define K_PARAM_SIZE 512 -/* This section allows to enable kernel debugging and timing functionality. - * For normal operation all options should be disabled. - */ -#define DEBUG_SCHED_CHECK 0 /* sanity check of scheduling queues */ -#define DEBUG_TIME_LOCKS 0 /* measure time spent in locks */ - #endif /* CONFIG_H */ diff --git a/kernel/const.h b/kernel/const.h index b8cd35263..1ef597629 100755 --- a/kernel/const.h +++ b/kernel/const.h @@ -6,6 +6,7 @@ #include #include "config.h" +#include "debug.h" /* Map a process number to a privilege structure id. */ #define s_nr_to_id(n) (NR_TASKS + (n) + 1) @@ -37,24 +38,15 @@ ( MAP_CHUNK(map.chunk,bit) &= ~(1 << CHUNK_OFFSET(bit) ) #define NR_SYS_CHUNKS BITMAP_CHUNKS(NR_SYS_PROCS) -#if DEBUG_LOCK_CHECK -#define reallock(c, v) { if(intr_disabled()) { kinfo.relocking++; } else { intr_disable(); } } -#else -#define reallock(c, v) intr_disable() -#endif +#define reallock do { int d; d = intr_disabled(); intr_disable(); locklevel++; if(d && locklevel == 1) { minix_panic("reallock while interrupts disabled first time", __LINE__); } } while(0) -#define realunlock(c) intr_enable() +#define realunlock do { if(!intr_disabled()) { minix_panic("realunlock while interrupts enabled", __LINE__); } if(locklevel < 1) { minix_panic("realunlock while locklevel below 1", __LINE__); } locklevel--; if(locklevel == 0) { intr_enable(); } } while(0) -#if DEBUG_TIME_LOCKS -#define lock(c, v) do { reallock(c, v); locktimestart(c, v); } while(0) -#define unlock(c) do { locktimeend(c); realunlock(c); } while(0) -#else /* Disable/ enable hardware interrupts. The parameters of lock() and unlock() * are used when debugging is enabled. See debug.h for more information. */ -#define lock(c, v) reallock(c, v) -#define unlock(c) realunlock(c) -#endif +#define lock reallock +#define unlock realunlock /* args to intr_init() */ #define INTS_ORIG 0 /* restore interrupts */ diff --git a/kernel/debug.c b/kernel/debug.c index eeb3b775e..16b96905e 100644 --- a/kernel/debug.c +++ b/kernel/debug.c @@ -6,12 +6,13 @@ #include "kernel.h" #include "proc.h" #include "debug.h" -#include -#if DEBUG_TIME_LOCKS /* only include code if enabled */ +#include +#include +#include + /* Data structures to store lock() timing data. */ -struct lock_timingdata timingdata[TIMING_CATEGORIES]; static unsigned long starttimes[TIMING_CATEGORIES][2]; #define HIGHCOUNT 0 @@ -100,69 +101,75 @@ void timer_end(int cat) return; } -#endif /* DEBUG_TIME_LOCKS */ - #if DEBUG_SCHED_CHECK /* only include code if enabled */ #define MAX_LOOP (NR_PROCS + NR_TASKS) PUBLIC void -check_runqueues(char *when) +check_runqueues_f(char *file, int line) { int q, l = 0; register struct proc *xp; +#define MYPANIC(msg) { \ + static char buf[100]; \ + strcpy(buf, file); \ + strcat(buf, ": "); \ + util_nstrcat(buf, line);\ + strcat(buf, ": "); \ + strcat(buf, msg); \ + minix_panic(buf, NO_NUM); \ + } for (xp = BEG_PROC_ADDR; xp < END_PROC_ADDR; ++xp) { xp->p_found = 0; - if (l++ > MAX_LOOP) { panic("check error", NO_NUM); } + if (l++ > MAX_LOOP) { MYPANIC("check error"); } } for (q=l=0; q < NR_SCHED_QUEUES; q++) { if (rdy_head[q] && !rdy_tail[q]) { - kprintf("head but no tail in %d: %s", q, when); - panic("scheduling error", NO_NUM); + kprintf("head but no tail in %d\n", q); + MYPANIC("scheduling error"); } if (!rdy_head[q] && rdy_tail[q]) { - kprintf("tail but no head in %d: %s", q, when); - panic("scheduling error", NO_NUM); + kprintf("tail but no head in %d\n", q); + MYPANIC("scheduling error"); } if (rdy_tail[q] && rdy_tail[q]->p_nextready != NIL_PROC) { - kprintf("tail and tail->next not null in %d: %s", q, when); - panic("scheduling error", NO_NUM); + kprintf("tail and tail->next not null in %d\n", q); + MYPANIC("scheduling error"); } for(xp = rdy_head[q]; xp != NIL_PROC; xp = xp->p_nextready) { if (!xp->p_ready) { - kprintf("scheduling error: unready on runq %d proc %d: %s\n", - q, xp->p_nr, when); - panic("found unready process on run queue", NO_NUM); + kprintf("scheduling error: unready on runq %d proc %d\n", + q, xp->p_nr); + MYPANIC("found unready process on run queue"); } if (xp->p_priority != q) { - kprintf("scheduling error: wrong priority q %d proc %d: %s\n", - q, xp->p_nr, when); - panic("wrong priority", NO_NUM); + kprintf("scheduling error: wrong priority q %d proc %d\n", + q, xp->p_nr); + MYPANIC("wrong priority"); } if (xp->p_found) { - kprintf("scheduling error: double sched q %d proc %d: %s\n", - q, xp->p_nr, when); - panic("proc more than once on scheduling queue", NO_NUM); + kprintf("scheduling error: double sched q %d proc %d\n", + q, xp->p_nr); + MYPANIC("proc more than once on scheduling queue"); } xp->p_found = 1; if (xp->p_nextready == NIL_PROC && rdy_tail[q] != xp) { - kprintf("sched err: last element not tail q %d proc %d: %s\n", - q, xp->p_nr, when); - panic("scheduling error", NO_NUM); + kprintf("sched err: last element not tail q %d proc %d\n", + q, xp->p_nr); + MYPANIC("scheduling error"); } - if (l++ > MAX_LOOP) panic("loop in schedule queue?", NO_NUM); + if (l++ > MAX_LOOP) MYPANIC("loop in schedule queue?"); } } l = 0; for (xp = BEG_PROC_ADDR; xp < END_PROC_ADDR; ++xp) { if (! isemptyp(xp) && xp->p_ready && ! xp->p_found) { - kprintf("sched error: ready proc %d not on queue: %s\n", - xp->p_nr, when); - panic("ready proc not on scheduling queue", NO_NUM); - if (l++ > MAX_LOOP) { panic("loop in proc.t?", NO_NUM); } + kprintf("sched error: ready proc %d not on queue\n", xp->p_nr); + MYPANIC("ready proc not on scheduling queue"); + if (l++ > MAX_LOOP) { MYPANIC("loop in debug.c?"); } } } } diff --git a/kernel/debug.h b/kernel/debug.h index 2cfb905d0..b114a4a3a 100644 --- a/kernel/debug.h +++ b/kernel/debug.h @@ -21,36 +21,16 @@ */ #define DEBUG_ENABLE_IPC_WARNINGS 0 #define DEBUG_STACKTRACE 1 +#define DEBUG_VMASSERT 1 +#define DEBUG_SCHED_CHECK 1 +#define DEBUG_TIME_LOCKS 1 /* It's interesting to measure the time spent withing locked regions, because * this is the time that the system is deaf to interrupts. */ -#if DEBUG_TIME_LOCKS #define TIMING_POINTS 20 /* timing resolution */ #define TIMING_CATEGORIES 20 #define TIMING_NAME 10 -/* Definition of the data structure to store lock() timing data. */ -struct lock_timingdata { - char names[TIMING_NAME]; - unsigned long lock_timings[TIMING_POINTS]; - unsigned long lock_timings_range[2]; - unsigned long binsize, resets, misses, measurements; -}; - -/* The data is declared here, but allocated in debug.c. */ -extern struct lock_timingdata timingdata[TIMING_CATEGORIES]; - -/* Prototypes for the timing functionality. */ -_PROTOTYPE( void timer_start, (int cat, char *name) ); -_PROTOTYPE( void timer_end, (int cat) ); - -#define locktimestart(c, v) timer_start(c, v) -#define locktimeend(c) timer_end(c) -#else -#define locktimestart(c, v) -#define locktimeend(c) -#endif /* DEBUG_TIME_LOCKS */ - #endif /* DEBUG_H */ diff --git a/kernel/glo.h b/kernel/glo.h index 4566739b1..30468ab35 100755 --- a/kernel/glo.h +++ b/kernel/glo.h @@ -20,7 +20,6 @@ EXTERN char kernel_exception; /* TRUE after system exceptions */ EXTERN char shutdown_started; /* TRUE after shutdowns / reboots */ /* Kernel information structures. This groups vital kernel information. */ -EXTERN phys_bytes aout; /* address of a.out headers */ EXTERN struct kinfo kinfo; /* kernel information for users */ EXTERN struct machine machine; /* machine information for users */ EXTERN struct kmessages kmess; /* diagnostic messages in kernel */ @@ -32,6 +31,10 @@ EXTERN struct proc *prev_ptr; /* previously running process */ EXTERN struct proc *proc_ptr; /* pointer to currently running process */ EXTERN struct proc *next_ptr; /* next process to run after restart() */ EXTERN struct proc *bill_ptr; /* process to bill for clock ticks */ +EXTERN struct proc *vmrestart; /* first process on vmrestart queue */ +EXTERN struct proc *vmrequest; /* first process on vmrequest queue */ +EXTERN struct proc *pagefaults; /* first process on pagefault queue */ +EXTERN struct proc *softnotify; /* first process on softnotify queue */ EXTERN char k_reenter; /* kernel reentry count (entry count less 1) */ EXTERN unsigned lost_ticks; /* clock ticks counted outside clock task */ @@ -75,11 +78,25 @@ EXTERN endpoint_t who_e; /* message source endpoint */ EXTERN int who_p; /* message source proc */ EXTERN int sys_call_code; /* kernel call number in SYSTEM */ EXTERN time_t boottime; +EXTERN char params_buffer[512]; /* boot monitor parameters */ +EXTERN int minix_panicing; +EXTERN int locklevel; + +EXTERN unsigned long cr3switch; +EXTERN unsigned long cr3reload; /* VM */ EXTERN phys_bytes vm_base; EXTERN phys_bytes vm_size; EXTERN phys_bytes vm_mem_high; +EXTERN int vm_running; +EXTERN int must_notify_vm; + +/* Verbose flags (debugging). */ +EXTERN int verbose_vm; + +/* Timing measurements. */ +EXTERN struct lock_timingdata timingdata[TIMING_CATEGORIES]; /* Variables that are initialized elsewhere are just extern here. */ extern struct boot_image image[]; /* system image processes */ diff --git a/kernel/interrupt.c b/kernel/interrupt.c index 6d54fab22..3dffb72b6 100644 --- a/kernel/interrupt.c +++ b/kernel/interrupt.c @@ -30,7 +30,7 @@ PUBLIC void put_irq_handler( irq_hook_t* hook, int irq, irq_handler_t handler) irq_hook_t **line; if( irq < 0 || irq >= NR_IRQ_VECTORS ) - panic("invalid call to put_irq_handler", irq); + minix_panic("invalid call to put_irq_handler", irq); line = &irq_handlers[irq]; id = 1; @@ -42,7 +42,7 @@ PUBLIC void put_irq_handler( irq_hook_t* hook, int irq, irq_handler_t handler) } if(id == 0) - panic("Too many handlers for irq", irq); + minix_panic("Too many handlers for irq", irq); hook->next = NULL; hook->handler = handler; @@ -68,7 +68,7 @@ PUBLIC void rm_irq_handler( irq_hook_t* hook ) { irq_hook_t **line; if( irq < 0 || irq >= NR_IRQ_VECTORS ) - panic("invalid call to rm_irq_handler", irq); + minix_panic("invalid call to rm_irq_handler", irq); /* disable the irq. */ intr_mask(hook); diff --git a/kernel/ipc.h b/kernel/ipc.h index d315b852b..15c83afdc 100644 --- a/kernel/ipc.h +++ b/kernel/ipc.h @@ -14,10 +14,15 @@ #define RECEIVE 2 /* blocking receive */ #define SENDREC 3 /* SEND + RECEIVE */ #define NOTIFY 4 /* asynchronous notify */ -#define SENDNB 5 /* nonblocking send */ +#define SENDNB 5 /* nonblocking send */ #define SENDA 16 /* asynchronous send */ /* The following bit masks determine what checks that should be done. */ #define CHECK_DEADLOCK 0x03 /* 0000 0011 : check for deadlock */ +#define WILLRECEIVE(target, source_ep) \ + ((RTS_ISSET(target, RECEIVING) && !RTS_ISSET(target, SENDING)) && \ + (target->p_getfrom_e == ANY || target->p_getfrom_e == source_ep)) + + #endif /* IPC_H */ diff --git a/kernel/main.c b/kernel/main.c index f9ec99e20..00aa32d14 100755 --- a/kernel/main.c +++ b/kernel/main.c @@ -20,7 +20,6 @@ /* Prototype declarations for PRIVATE functions. */ FORWARD _PROTOTYPE( void announce, (void)); -FORWARD _PROTOTYPE( void shutdown, (timer_t *)); /*===========================================================================* * main * @@ -115,11 +114,11 @@ PUBLIC void main() hdrindex = 1 + i-NR_TASKS; /* servers, drivers, INIT */ } - /* The bootstrap loader created an array of the a.out headers at - * absolute address 'aout'. Get one element to e_hdr. + /* Architecture-specific way to find out aout header of this + * boot process. */ - phys_copy(aout + hdrindex * A_MINHDR, vir2phys(&e_hdr), - (phys_bytes) A_MINHDR); + arch_get_aout_headers(hdrindex, &e_hdr); + /* Convert addresses to clicks and build process memory map */ text_base = e_hdr.a_syms >> CLICK_SHIFT; text_clicks = (e_hdr.a_text + CLICK_SIZE-1) >> CLICK_SHIFT; @@ -156,8 +155,8 @@ PUBLIC void main() } /* Set ready. The HARDWARE task is never ready. */ - if (rp->p_nr == HARDWARE) RTS_LOCK_SET(rp, NO_PRIORITY); - RTS_LOCK_UNSET(rp, SLOT_FREE); /* remove SLOT_FREE and schedule */ + if (rp->p_nr == HARDWARE) RTS_SET(rp, NO_PRIORITY); + RTS_UNSET(rp, SLOT_FREE); /* remove SLOT_FREE and schedule */ /* Code and data segments must be allocated in protected mode. */ alloc_segments(rp); @@ -170,6 +169,8 @@ PUBLIC void main() cprof_procs_no = 0; /* init nr of hash table slots used */ #endif /* CPROFILE */ + vm_running = 0; + /* MINIX is now ready. All boot image processes are on the ready queue. * Return to the assembly code to start running the current process. */ @@ -203,34 +204,19 @@ int how; register struct proc *rp; message m; - /* Send a signal to all system processes that are still alive to inform - * them that the MINIX kernel is shutting down. A proper shutdown sequence - * should be implemented by a user-space server. This mechanism is useful - * as a backup in case of system panics, so that system processes can still - * run their shutdown code, e.g, to synchronize the FS or to let the TTY - * switch to the first console. - */ -#if DEAD_CODE - kprintf("Sending SIGKSTOP to system processes ...\n"); - for (rp=BEG_PROC_ADDR; rps_flags & SYS_PROC) && !iskernelp(rp)) - send_sig(proc_nr(rp), SIGKSTOP); - } -#endif - /* Continue after 1 second, to give processes a chance to get scheduled to * do shutdown work. Set a watchog timer to call shutdown(). The timer * argument passes the shutdown status. */ kprintf("MINIX will now be shut down ...\n"); tmr_arg(&shutdown_timer)->ta_int = how; - set_timer(&shutdown_timer, get_uptime() + HZ, shutdown); + set_timer(&shutdown_timer, get_uptime() + 5*HZ, minix_shutdown); } /*===========================================================================* * shutdown * *===========================================================================*/ -PRIVATE void shutdown(tp) +PUBLIC void minix_shutdown(tp) timer_t *tp; { /* This function is called from prepare_shutdown or stop_sequence to bring @@ -239,6 +225,6 @@ timer_t *tp; */ intr_init(INTS_ORIG); clock_stop(); - arch_shutdown(tmr_arg(tp)->ta_int); + arch_shutdown(tp ? tmr_arg(tp)->ta_int : RBT_PANIC); } diff --git a/kernel/proc.c b/kernel/proc.c index c405a2c91..692eafb4c 100755 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -39,22 +39,24 @@ #include #include #include -#include "debug.h" -#include "kernel.h" -#include "proc.h" #include #include #include #include +#include "debug.h" +#include "kernel.h" +#include "proc.h" +#include "vm.h" + /* Scheduling and message passing functions. The functions are available to * other parts of the kernel through lock_...(). The lock temporarily disables * interrupts to prevent race conditions. */ FORWARD _PROTOTYPE( int mini_send, (struct proc *caller_ptr, int dst_e, - message *m_ptr, unsigned flags)); + message *m_ptr, int flags)); FORWARD _PROTOTYPE( int mini_receive, (struct proc *caller_ptr, int src, - message *m_ptr, unsigned flags)); + message *m_ptr, int flags)); FORWARD _PROTOTYPE( int mini_notify, (struct proc *caller_ptr, int dst)); FORWARD _PROTOTYPE( int mini_senda, (struct proc *caller_ptr, asynmsg_t *table, size_t size)); @@ -62,8 +64,6 @@ FORWARD _PROTOTYPE( int deadlock, (int function, register struct proc *caller, int src_dst)); FORWARD _PROTOTYPE( int try_async, (struct proc *caller_ptr)); FORWARD _PROTOTYPE( int try_one, (struct proc *src_ptr, struct proc *dst_ptr)); -FORWARD _PROTOTYPE( void enqueue, (struct proc *rp)); -FORWARD _PROTOTYPE( void dequeue, (struct proc *rp)); FORWARD _PROTOTYPE( void sched, (struct proc *rp, int *queue, int *front)); FORWARD _PROTOTYPE( void pick_proc, (void)); @@ -82,10 +82,51 @@ FORWARD _PROTOTYPE( void pick_proc, (void)); break; \ } -#define CopyMess(s,sp,sm,dp,dm) \ - cp_mess(proc_addr(s)->p_endpoint, \ - (sp)->p_memmap[D].mem_phys, \ - (vir_bytes)sm, (dp)->p_memmap[D].mem_phys, (vir_bytes)dm) +#define CopyMess(s,sp,sm,dp,dm) do { \ + vir_bytes dstlin; \ + endpoint_t e = proc_addr(s)->p_endpoint; \ + struct vir_addr src, dst; \ + int r; \ + timer_start(0, "copymess"); \ + if((dstlin = umap_local((dp), D, (vir_bytes) dm, sizeof(message))) == 0){\ + minix_panic("CopyMess: umap_local failed", __LINE__); \ + } \ + \ + if(vm_running && \ + (r=vm_checkrange((dp), (dp), dstlin, sizeof(message), 1, 0)) != OK) { \ + if(r != VMSUSPEND) \ + minix_panic("CopyMess: vm_checkrange error", __LINE__); \ + (dp)->p_vmrequest.saved.msgcopy.dst = (dp); \ + (dp)->p_vmrequest.saved.msgcopy.dst_v = (vir_bytes) dm; \ + if(data_copy((sp)->p_endpoint, \ + (vir_bytes) (sm), SYSTEM, \ + (vir_bytes) &(dp)->p_vmrequest.saved.msgcopy.msgbuf, \ + sizeof(message)) != OK) { \ + minix_panic("CopyMess: data_copy failed", __LINE__);\ + } \ + (dp)->p_vmrequest.saved.msgcopy.msgbuf.m_source = e; \ + (dp)->p_vmrequest.type = VMSTYPE_MSGCOPY; \ + } else { \ + src.proc_nr_e = (sp)->p_endpoint; \ + dst.proc_nr_e = (dp)->p_endpoint; \ + src.segment = dst.segment = D; \ + src.offset = (vir_bytes) (sm); \ + dst.offset = (vir_bytes) (dm); \ + if(virtual_copy(&src, &dst, sizeof(message)) != OK) { \ + kprintf("copymess: copy %d:%lx to %d:%lx failed\n",\ + (sp)->p_endpoint, (sm), (dp)->p_endpoint, dm);\ + minix_panic("CopyMess: virtual_copy (1) failed", __LINE__); \ + } \ + src.proc_nr_e = SYSTEM; \ + src.offset = (vir_bytes) &e; \ + if(virtual_copy(&src, &dst, sizeof(e)) != OK) { \ + kprintf("copymess: copy %d:%lx to %d:%lx\n", \ + (sp)->p_endpoint, (sm), (dp)->p_endpoint, dm);\ + minix_panic("CopyMess: virtual_copy (2) failed", __LINE__); \ + } \ + } \ + timer_end(0); \ +} while(0) /*===========================================================================* * sys_call * @@ -105,11 +146,25 @@ long bit_map; /* notification event set or flags */ int group_size; /* used for deadlock check */ int result; /* the system call's result */ int src_dst_p; /* Process slot number */ - vir_clicks vlo, vhi; /* virtual clicks containing message to send */ + size_t msg_size; if (caller_ptr->p_endpoint == ipc_stats_target) ipc_stats.total= add64u(ipc_stats.total, 1); +#if 0 + if(src_dst_e != 4 && src_dst_e != 5 && + caller_ptr->p_endpoint != 4 && caller_ptr->p_endpoint != 5) { + if(call_nr == SEND) + kprintf("(%d SEND to %d) ", caller_ptr->p_endpoint, src_dst_e); + else if(call_nr == RECEIVE) + kprintf("(%d RECEIVE from %d) ", caller_ptr->p_endpoint, src_dst_e); + else if(call_nr == SENDREC) + kprintf("(%d SENDREC to %d) ", caller_ptr->p_endpoint, src_dst_e); + else + kprintf("(%d %d to/from %d) ", caller_ptr->p_endpoint, call_nr, src_dst_e); + } +#endif + #if 1 if (RTS_ISSET(caller_ptr, SLOT_FREE)) { @@ -122,10 +177,10 @@ long bit_map; /* notification event set or flags */ /* Check destination. SENDA is special because its argument is a table and * not a single destination. RECEIVE is the only call that accepts ANY (in - * addition to a real endpoint). The other calls (SEND, SENDNB, SENDREC, + * addition to a real endpoint). The other calls (SEND, SENDREC, * and NOTIFY) require an endpoint to corresponds to a process. In addition, - * it is necessary to check whether a process is allow to send to a given - * destination. For SENDREC we check s_ipc_sendrec, and for SEND, SENDNB, + * it is necessary to check whether a process is allowed to send to a given + * destination. For SENDREC we check s_ipc_sendrec, and for SEND, * and NOTIFY we check s_ipc_to. */ if (call_nr == SENDA) @@ -150,7 +205,6 @@ long bit_map; /* notification event set or flags */ { /* Require a valid source and/or destination process. */ if(!isokendpt(src_dst_e, &src_dst_p)) { -if (src_dst_e == 0) panic("sys_call: no PM", NO_NUM); #if DEBUG_ENABLE_IPC_WARNINGS kprintf("sys_call: trap %d by %d with bad endpoint %d\n", call_nr, proc_nr(caller_ptr), src_dst_e); @@ -160,7 +214,7 @@ if (src_dst_e == 0) panic("sys_call: no PM", NO_NUM); return EDEADSRCDST; } - /* If the call is to send to a process, i.e., for SEND, SENDNB, + /* If the call is to send to a process, i.e., for SEND, * SENDREC or NOTIFY, verify that the caller is allowed to send to * the given destination. */ @@ -224,40 +278,85 @@ if (src_dst_e == 0) panic("sys_call: no PM", NO_NUM); if ((iskerneln(src_dst_p) && call_nr != SENDREC && call_nr != RECEIVE)) { #if DEBUG_ENABLE_IPC_WARNINGS kprintf("sys_call: trap %d not allowed, caller %d, src_dst %d\n", - call_nr, proc_nr(caller_ptr), src_dst); + call_nr, proc_nr(caller_ptr), src_dst_e); #endif if (caller_ptr->p_endpoint == ipc_stats_target) ipc_stats.call_not_allowed++; return(ETRAPDENIED); /* trap denied by mask or kernel */ } - /* If the call involves a message buffer, i.e., for SEND, SENDNB, SENDREC, + /* Get and check the size of the argument in bytes. + * Normally this is just the size of a regular message, but in the + * case of SENDA the argument is a table. + */ + if(call_nr == SENDA) { + msg_size = (size_t) src_dst_e; + + /* Limit size to something reasonable. An arbitrary choice is 16 + * times the number of process table entries. + */ + if (msg_size > 16*(NR_TASKS + NR_PROCS)) + return EDOM; + msg_size *= sizeof(asynmsg_t); /* convert to bytes */ + } else { + msg_size = sizeof(*m_ptr); + } + + /* If the call involves a message buffer, i.e., for SEND, SENDREC, * or RECEIVE, check the message pointer. This check allows a message to be * anywhere in data or stack or gap. It will have to be made more elaborate * for machines which don't have the gap mapped. + * + * We use msg_size decided above. */ - if (call_nr == SEND || call_nr == SENDNB || call_nr == SENDREC || - call_nr == RECEIVE) { - vlo = (vir_bytes) m_ptr >> CLICK_SHIFT; - vhi = ((vir_bytes) m_ptr + MESS_SIZE - 1) >> CLICK_SHIFT; - if (vlo < caller_ptr->p_memmap[D].mem_vir || vlo > vhi || - vhi >= caller_ptr->p_memmap[S].mem_vir + - caller_ptr->p_memmap[S].mem_len) { -#if DEBUG_ENABLE_IPC_WARNINGS - kprintf( - "sys_call: invalid message pointer, trap %d, caller %d\n", - call_nr, proc_nr(caller_ptr)); -#endif - if (caller_ptr->p_endpoint == ipc_stats_target) - ipc_stats.bad_buffer++; - return(EFAULT); /* invalid message pointer */ + if (call_nr == SEND || call_nr == SENDREC || + call_nr == RECEIVE || call_nr == SENDA || call_nr == SENDNB) { + int r; + phys_bytes lin; + + /* Map to linear address. */ + if((lin = umap_local(caller_ptr, D, (vir_bytes) m_ptr, msg_size)) == 0) + return EFAULT; + + /* Check if message pages in calling process are mapped. + * We don't have to check the recipient if this is a send, + * because this code will do that before its receive() starts. + * + * It is important the range is verified as _writable_, because + * the kernel will want to write to the SENDA buffer in the future, + * and those pages may not be shared between processes. + */ + + if(vm_running && + (r=vm_checkrange(caller_ptr, caller_ptr, lin, msg_size, 1, 0)) != OK) { + if(r != VMSUSPEND) { + kprintf("SYSTEM:sys_call:vm_checkrange: err %d\n", r); + return r; + } + minix_panic("vmsuspend", __LINE__); + + /* We can't go ahead with this call. Caller is suspended + * and we have to save the state in its process struct. + */ + caller_ptr->p_vmrequest.saved.sys_call.call_nr = call_nr; + caller_ptr->p_vmrequest.saved.sys_call.m_ptr = m_ptr; + caller_ptr->p_vmrequest.saved.sys_call.src_dst_e = src_dst_e; + caller_ptr->p_vmrequest.saved.sys_call.bit_map = bit_map; + caller_ptr->p_vmrequest.type = VMSTYPE_SYS_CALL; + + kprintf("SYSTEM: %s:%d: suspending call 0x%lx on ipc buffer 0x%lx\n", + caller_ptr->p_name, caller_ptr->p_endpoint, call_nr, m_ptr); + + /* vm_checkrange() will have suspended caller with VMREQUEST. */ + return OK; } - } + + } /* Check for a possible deadlock for blocking SEND(REC) and RECEIVE. */ if (call_nr == SEND || call_nr == SENDREC || call_nr == RECEIVE) { if (group_size = deadlock(call_nr, caller_ptr, src_dst_p)) { -#if DEBUG_ENABLE_IPC_WARNINGS +#if 0 kprintf("sys_call: trap %d from %d to %d deadlocked, group size %d\n", call_nr, proc_nr(caller_ptr), src_dst_p, group_size); #endif @@ -273,7 +372,6 @@ if (src_dst_e == 0) panic("sys_call: no PM", NO_NUM); * - SEND: sender blocks until its message has been delivered * - RECEIVE: receiver blocks until an acceptable message has arrived * - NOTIFY: asynchronous call; deliver notification or mark pending - * - SENDNB: nonblocking send * - SENDA: list of asynchronous send requests */ switch(call_nr) { @@ -282,21 +380,21 @@ if (src_dst_e == 0) panic("sys_call: no PM", NO_NUM); caller_ptr->p_misc_flags |= REPLY_PENDING; /* fall through */ case SEND: - result = mini_send(caller_ptr, src_dst_e, m_ptr, 0 /*flags*/); + result = mini_send(caller_ptr, src_dst_e, m_ptr, 0); if (call_nr == SEND || result != OK) break; /* done, or SEND failed */ /* fall through for SENDREC */ case RECEIVE: if (call_nr == RECEIVE) caller_ptr->p_misc_flags &= ~REPLY_PENDING; - result = mini_receive(caller_ptr, src_dst_e, m_ptr, 0 /*flags*/); + result = mini_receive(caller_ptr, src_dst_e, m_ptr, 0); break; case NOTIFY: result = mini_notify(caller_ptr, src_dst_p); break; - case SENDNB: - result = mini_send(caller_ptr, src_dst_e, m_ptr, NON_BLOCKING); - break; + case SENDNB: + result = mini_send(caller_ptr, src_dst_e, m_ptr, NON_BLOCKING); + break; case SENDA: result = mini_senda(caller_ptr, (asynmsg_t *)m_ptr, (size_t)src_dst_e); break; @@ -325,10 +423,17 @@ int src_dst; /* src or dst process */ register struct proc *xp; /* process pointer */ int group_size = 1; /* start with only caller */ int trap_flags; +#if DEBUG_ENABLE_IPC_WARNINGS + static struct proc *processes[NR_PROCS + NR_TASKS]; + processes[0] = cp; +#endif while (src_dst != ANY) { /* check while process nr */ int src_dst_e; xp = proc_addr(src_dst); /* follow chain of processes */ +#if DEBUG_ENABLE_IPC_WARNINGS + processes[group_size] = xp; +#endif group_size ++; /* extra process in group */ /* Check whether the last process in the chain has a dependency. If it @@ -354,12 +459,38 @@ int src_dst; /* src or dst process */ return(0); /* not a deadlock */ } } +#if DEBUG_ENABLE_IPC_WARNINGS + { + int i; + kprintf("deadlock between these processes:\n"); + for(i = 0; i < group_size; i++) { + kprintf(" %10s ", processes[i]->p_name); + proc_stacktrace(processes[i]); + } + } +#endif return(group_size); /* deadlock found */ } } return(0); /* not a deadlock */ } +/*===========================================================================* + * sys_call_restart * + *===========================================================================*/ +PUBLIC void sys_call_restart(caller) +struct proc *caller; +{ + int r; + minix_panic("sys_call_restart", NO_NUM); + kprintf("restarting sys_call code 0x%lx, " + "m_ptr 0x%lx, srcdst %d, bitmap 0x%lx, but not really\n", + caller->p_vmrequest.saved.sys_call.call_nr, + caller->p_vmrequest.saved.sys_call.m_ptr, + caller->p_vmrequest.saved.sys_call.src_dst_e, + caller->p_vmrequest.saved.sys_call.bit_map); + caller->p_reg.retreg = r; +} /*===========================================================================* * mini_send * @@ -368,7 +499,7 @@ PRIVATE int mini_send(caller_ptr, dst_e, m_ptr, flags) register struct proc *caller_ptr; /* who is trying to send a message? */ int dst_e; /* to whom is message being sent? */ message *m_ptr; /* pointer to message buffer */ -unsigned flags; /* system call flags */ +int flags; { /* Send a message from 'caller_ptr' to 'dst'. If 'dst' is blocked waiting * for this message, copy the message to it and unblock 'dst'. If 'dst' is @@ -391,14 +522,18 @@ unsigned flags; /* system call flags */ /* Check if 'dst' is blocked waiting for this message. The destination's * SENDING flag may be set when its SENDREC call blocked while sending. */ - if ( (RTS_ISSET(dst_ptr, RECEIVING) && !RTS_ISSET(dst_ptr, SENDING)) && - (dst_ptr->p_getfrom_e == ANY - || dst_ptr->p_getfrom_e == caller_ptr->p_endpoint)) { + if (WILLRECEIVE(dst_ptr, caller_ptr->p_endpoint)) { /* Destination is indeed waiting for this message. */ CopyMess(caller_ptr->p_nr, caller_ptr, m_ptr, dst_ptr, dst_ptr->p_messbuf); RTS_UNSET(dst_ptr, RECEIVING); - } else if ( ! (flags & NON_BLOCKING)) { + } else { + if(flags & NON_BLOCKING) { + if (caller_ptr->p_endpoint == ipc_stats_target) + ipc_stats.not_ready++; + return(ENOTREADY); + } + /* Destination is not waiting. Block and dequeue caller. */ caller_ptr->p_messbuf = m_ptr; RTS_SET(caller_ptr, SENDING); @@ -409,10 +544,6 @@ unsigned flags; /* system call flags */ while (*xpp != NIL_PROC) xpp = &(*xpp)->p_q_link; *xpp = caller_ptr; /* add caller to end */ caller_ptr->p_q_link = NIL_PROC; /* mark new end of list */ - } else { - if (caller_ptr->p_endpoint == ipc_stats_target) - ipc_stats.not_ready++; - return(ENOTREADY); } return(OK); } @@ -424,11 +555,11 @@ PRIVATE int mini_receive(caller_ptr, src_e, m_ptr, flags) register struct proc *caller_ptr; /* process trying to get message */ int src_e; /* which message source is wanted */ message *m_ptr; /* pointer to message buffer */ -unsigned flags; /* system call flags */ +int flags; { /* A process or task wants to get a message. If a message is already queued, * acquire it and deblock the sender. If no message from the desired source - * is available block the caller, unless the flags don't allow blocking. + * is available block the caller. */ register struct proc **xpp; register struct notification **ntf_q_pp; @@ -491,7 +622,9 @@ unsigned flags; /* system call flags */ #if 1 if (RTS_ISSET(*xpp, SLOT_FREE)) { - kprintf("listening to the dead?!?\n"); + kprintf("%d: receive from %d; found dead %d (%s)?\n", + caller_ptr->p_endpoint, src_e, (*xpp)->p_endpoint, + (*xpp)->p_name); if (caller_ptr->p_endpoint == ipc_stats_target) ipc_stats.deadproc++; return EINVAL; @@ -580,6 +713,28 @@ int dst; /* which process to notify */ return(OK); } +#define ASCOMPLAIN(caller, entry, field) \ + kprintf("kernel:%s:%d: asyn failed for %s in %s " \ + "(%d/%d, tab 0x%lx)\n",__FILE__,__LINE__, \ +field, caller->p_name, entry, priv(caller)->s_asynsize, priv(caller)->s_asyntab) + +#define A_RETRIEVE(entry, field) \ + if(data_copy(caller_ptr->p_endpoint, \ + table_v + (entry)*sizeof(asynmsg_t) + offsetof(struct asynmsg,field),\ + SYSTEM, (vir_bytes) &tabent.field, \ + sizeof(tabent.field)) != OK) {\ + ASCOMPLAIN(caller_ptr, entry, #field); \ + return EFAULT; \ + } + +#define A_INSERT(entry, field) \ + if(data_copy(SYSTEM, (vir_bytes) &tabent.field, \ + caller_ptr->p_endpoint, \ + table_v + (entry)*sizeof(asynmsg_t) + offsetof(struct asynmsg,field),\ + sizeof(tabent.field)) != OK) {\ + ASCOMPLAIN(caller_ptr, entry, #field); \ + return EFAULT; \ + } /*===========================================================================* * mini_senda * @@ -591,11 +746,11 @@ size_t size; { int i, dst_p, done, do_notify; unsigned flags; - phys_bytes tab_phys; struct proc *dst_ptr; struct priv *privp; message *m_ptr; asynmsg_t tabent; + vir_bytes table_v = (vir_bytes) table; privp= priv(caller_ptr); if (!(privp->s_flags & SYS_PROC)) @@ -619,6 +774,9 @@ size_t size; /* Limit size to something reasonable. An arbitrary choice is 16 * times the number of process table entries. + * + * (this check has been duplicated in sys_call but is left here + * as a sanity check) */ if (size > 16*(NR_TASKS + NR_PROCS)) { @@ -627,26 +785,14 @@ size_t size; return EDOM; } - /* Map table */ - tab_phys= umap_local(caller_ptr, D, (vir_bytes)table, - size*sizeof(table[0])); - if (tab_phys == 0) - { - kprintf("mini_senda: got bad table pointer/size\n"); - if (caller_ptr->p_endpoint == ipc_stats_target) - ipc_stats.bad_buffer++; - return EFAULT; - } - /* Scan the table */ do_notify= FALSE; done= TRUE; for (i= 0; ip_rts_flags & NO_ENDPOINT) { tabent.result= EDSTDIED; - phys_copy(vir2phys(&tabent.result), - tab_phys + i*sizeof(table[0]) + - offsetof(struct asynmsg, result), - sizeof(tabent.result)); + A_INSERT(i, result); tabent.flags= flags | AMF_DONE; - phys_copy(vir2phys(&tabent.flags), - tab_phys + i*sizeof(table[0]) + - offsetof(struct asynmsg, flags), - sizeof(tabent.flags)); + A_INSERT(i, flags); if (flags & AMF_NOTIFY) do_notify= TRUE; @@ -732,19 +864,12 @@ size_t size; CopyMess(caller_ptr->p_nr, caller_ptr, m_ptr, dst_ptr, dst_ptr->p_messbuf); - if ((dst_ptr->p_rts_flags &= ~RECEIVING) == 0) - enqueue(dst_ptr); + RTS_UNSET(dst_ptr, RECEIVING); tabent.result= OK; - phys_copy(vir2phys(&tabent.result), - tab_phys + i*sizeof(table[0]) + - offsetof(struct asynmsg, result), - sizeof(tabent.result)); + A_INSERT(i, result); tabent.flags= flags | AMF_DONE; - phys_copy(vir2phys(&tabent.flags), - tab_phys + i*sizeof(table[0]) + - offsetof(struct asynmsg, flags), - sizeof(tabent.flags)); + A_INSERT(i, flags); if (flags & AMF_NOTIFY) do_notify= 1; @@ -759,11 +884,18 @@ size_t size; } } if (do_notify) - kprintf("mini_senda: should notifiy caller\n"); + kprintf("mini_senda: should notify caller\n"); if (!done) { privp->s_asyntab= (vir_bytes)table; privp->s_asynsize= size; +#if 0 + if(caller_ptr->p_endpoint > INIT_PROC_NR) { + kprintf("kernel: %s (%d) asynsend table at 0x%lx, %d\n", + caller_ptr->p_name, caller_ptr->p_endpoint, + table, size); + } +#endif } return OK; } @@ -814,38 +946,27 @@ struct proc *dst_ptr; unsigned flags; size_t size; endpoint_t dst_e; - phys_bytes tab_phys; asynmsg_t *table_ptr; message *m_ptr; struct priv *privp; asynmsg_t tabent; + vir_bytes table_v; + struct proc *caller_ptr; privp= priv(src_ptr); size= privp->s_asynsize; + table_v = privp->s_asyntab; + caller_ptr = src_ptr; dst_e= dst_ptr->p_endpoint; - /* Map table */ - tab_phys= umap_local(src_ptr, D, privp->s_asyntab, - size*sizeof(tabent)); - if (tab_phys == 0) - { - kprintf("try_one: got bad table pointer/size\n"); - privp->s_asynsize= 0; - if (src_ptr->p_endpoint == ipc_stats_target) - ipc_stats.bad_buffer++; - return EFAULT; - } - /* Scan the table */ do_notify= FALSE; done= TRUE; for (i= 0; ip_messbuf); tabent.result= OK; - phys_copy(vir2phys(&tabent.result), - tab_phys + i*sizeof(tabent) + - offsetof(struct asynmsg, result), - sizeof(tabent.result)); + A_INSERT(i, result); tabent.flags= flags | AMF_DONE; - phys_copy(vir2phys(&tabent.flags), - tab_phys + i*sizeof(tabent) + - offsetof(struct asynmsg, flags), - sizeof(tabent.flags)); + A_INSERT(i, flags); if (flags & AMF_NOTIFY) { @@ -941,17 +1054,54 @@ int dst_e; /* (endpoint) who is to be notified */ /* Call from task level, locking is required. */ else { - lock(0, "notify"); + lock; result = mini_notify(proc_addr(src), dst); - unlock(0); + unlock; } return(result); } +/*===========================================================================* + * soft_notify * + *===========================================================================*/ +PUBLIC int soft_notify(dst_e) +int dst_e; /* (endpoint) who is to be notified */ +{ + int dst, u = 0; + struct proc *dstp, *sys = proc_addr(SYSTEM); + +/* Delayed interface to notify() from SYSTEM that is safe/easy to call + * from more places than notify(). + */ + if(!intr_disabled()) { lock; u = 1; } + + { + if(!isokendpt(dst_e, &dst)) + minix_panic("soft_notify to dead ep", dst_e); + + dstp = proc_addr(dst); + + if(!dstp->p_softnotified) { + dstp->next_soft_notify = softnotify; + softnotify = dstp; + dstp->p_softnotified = 1; + + if (RTS_ISSET(sys, RECEIVING)) { + sys->p_messbuf->m_source = SYSTEM; + RTS_UNSET(sys, RECEIVING); + } + } + } + + if(u) { unlock; } + + return OK; +} + /*===========================================================================* * enqueue * *===========================================================================*/ -PRIVATE void enqueue(rp) +PUBLIC void enqueue(rp) register struct proc *rp; /* this process is now runnable */ { /* Add 'rp' to one of the queues of runnable processes. This function is @@ -963,8 +1113,9 @@ register struct proc *rp; /* this process is now runnable */ int front; /* add to front or back */ #if DEBUG_SCHED_CHECK - check_runqueues("enqueue1"); - if (rp->p_ready) kprintf("enqueue() already ready process\n"); + if(!intr_disabled()) { minix_panic("enqueue with interrupts enabled", NO_NUM); } + CHECK_RUNQUEUES; + if (rp->p_ready) minix_panic("enqueue already ready process", NO_NUM); #endif /* Determine where to insert to process. */ @@ -996,14 +1147,14 @@ register struct proc *rp; /* this process is now runnable */ #if DEBUG_SCHED_CHECK rp->p_ready = 1; - check_runqueues("enqueue2"); + CHECK_RUNQUEUES; #endif } /*===========================================================================* * dequeue * *===========================================================================*/ -PRIVATE void dequeue(rp) +PUBLIC void dequeue(rp) register struct proc *rp; /* this process is no longer runnable */ { /* A process must be removed from the scheduling queues, for example, because @@ -1017,12 +1168,13 @@ register struct proc *rp; /* this process is no longer runnable */ /* Side-effect for kernel: check if the task's stack still is ok? */ if (iskernelp(rp)) { if (*priv(rp)->s_stack_guard != STACK_GUARD) - panic("stack overrun by task", proc_nr(rp)); + minix_panic("stack overrun by task", proc_nr(rp)); } #if DEBUG_SCHED_CHECK - check_runqueues("dequeue1"); - if (! rp->p_ready) kprintf("dequeue() already unready process\n"); + CHECK_RUNQUEUES; + if(!intr_disabled()) { minix_panic("dequeue with interrupts enabled", NO_NUM); } + if (! rp->p_ready) minix_panic("dequeue() already unready process", NO_NUM); #endif /* Now make sure that the process is not in its ready queue. Remove the @@ -1045,7 +1197,7 @@ register struct proc *rp; /* this process is no longer runnable */ #if DEBUG_SCHED_CHECK rp->p_ready = 0; - check_runqueues("dequeue2"); + CHECK_RUNQUEUES; #endif } @@ -1101,12 +1253,16 @@ PRIVATE void pick_proc() for (q=0; q < NR_SCHED_QUEUES; q++) { if ( (rp = rdy_head[q]) != NIL_PROC) { next_ptr = rp; /* run process 'rp' next */ +#if 0 + if(rp->p_endpoint != 4 && rp->p_endpoint != 5 && rp->p_endpoint != IDLE && rp->p_endpoint != SYSTEM) + kprintf("[run %s]", rp->p_name); +#endif if (priv(rp)->s_flags & BILLABLE) bill_ptr = rp; /* bill for system time */ return; } } - panic("no ready process", NO_NUM); + minix_panic("no ready process", NO_NUM); } /*===========================================================================* @@ -1127,7 +1283,7 @@ timer_t *tp; /* watchdog timer pointer */ for (rp=BEG_PROC_ADDR; rpp_priority > rp->p_max_priority) { /* update priority? */ if (rp->p_rts_flags == 0) dequeue(rp); /* take off queue */ ticks_added += rp->p_quantum_size; /* do accounting */ @@ -1138,7 +1294,7 @@ timer_t *tp; /* watchdog timer pointer */ ticks_added += rp->p_quantum_size - rp->p_ticks_left; rp->p_ticks_left = rp->p_quantum_size; /* give new quantum */ } - unlock(5); + unlock; } } #if DEBUG @@ -1161,9 +1317,9 @@ message *m_ptr; /* pointer to message buffer */ { /* Safe gateway to mini_send() for tasks. */ int result; - lock(2, "send"); - result = mini_send(proc_ptr, dst_e, m_ptr, NON_BLOCKING); - unlock(2); + lock; + result = mini_send(proc_ptr, dst_e, m_ptr, 0); + unlock; return(result); } @@ -1174,9 +1330,9 @@ PUBLIC void lock_enqueue(rp) struct proc *rp; /* this process is now runnable */ { /* Safe gateway to enqueue() for tasks. */ - lock(3, "enqueue"); + lock; enqueue(rp); - unlock(3); + unlock; } /*===========================================================================* @@ -1192,12 +1348,24 @@ struct proc *rp; /* this process is no longer runnable */ */ dequeue(rp); } else { - lock(4, "dequeue"); + lock; dequeue(rp); - unlock(4); + unlock; } } +/*===========================================================================* + * endpoint_lookup * + *===========================================================================*/ +PUBLIC struct proc *endpoint_lookup(endpoint_t e) +{ + int n; + + if(!isokendpt(e, &n)) return NULL; + + return proc_addr(n); +} + /*===========================================================================* * isokendpt_f * *===========================================================================*/ @@ -1228,22 +1396,29 @@ int *p, fatalflag; *p = _ENDPOINT_P(e); if(!isokprocn(*p)) { #if DEBUG_ENABLE_IPC_WARNINGS +#if 0 kprintf("kernel:%s:%d: bad endpoint %d: proc %d out of range\n", file, line, e, *p); +#endif #endif } else if(isemptyn(*p)) { #if DEBUG_ENABLE_IPC_WARNINGS +#if 0 kprintf("kernel:%s:%d: bad endpoint %d: proc %d empty\n", file, line, e, *p); +#endif #endif } else if(proc_addr(*p)->p_endpoint != e) { #if DEBUG_ENABLE_IPC_WARNINGS +#if 0 kprintf("kernel:%s:%d: bad endpoint %d: proc %d has ept %d (generation %d vs. %d)\n", file, line, e, *p, proc_addr(*p)->p_endpoint, _ENDPOINT_G(e), _ENDPOINT_G(proc_addr(*p)->p_endpoint)); +#endif #endif } else ok = 1; if(!ok && fatalflag) { - panic("invalid endpoint ", e); + minix_panic("invalid endpoint ", e); } return ok; } + diff --git a/kernel/proc.h b/kernel/proc.h index 39ee9aecb..ad5b2b117 100755 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -27,6 +27,8 @@ struct proc { char p_quantum_size; /* quantum size in ticks */ struct mem_map p_memmap[NR_LOCAL_SEGS]; /* memory map (T, D, S) */ + struct pagefault p_pagefault; /* valid if PAGEFAULT in p_rts_flags set */ + struct proc *p_nextpagefault; /* next on PAGEFAULT chain */ clock_t p_user_time; /* user time in ticks */ clock_t p_sys_time; /* sys time in ticks */ @@ -44,6 +46,62 @@ struct proc { endpoint_t p_endpoint; /* endpoint number, generation-aware */ + /* If handler functions detect a process wants to do something with + * memory that isn't present, VM has to fix it. Until it has asked + * what needs to be done and fixed it, save necessary state here. + * + * The requester gets a copy of its request message in reqmsg and gets + * VMREQUEST set. + */ + struct { + struct proc *nextrestart; /* next in vmrestart chain */ + struct proc *nextrequestor; /* next in vmrequest chain */ +#define VMSTYPE_SYS_NONE 0 +#define VMSTYPE_SYS_MESSAGE 1 +#define VMSTYPE_SYS_CALL 2 +#define VMSTYPE_MSGCOPY 3 + int type; /* suspended operation */ + union { + /* VMSTYPE_SYS_MESSAGE */ + message reqmsg; /* suspended request message */ + + /* VMSTYPE_SYS_CALL */ + struct { + int call_nr; + message *m_ptr; + int src_dst_e; + long bit_map; + } sys_call; + + /* VMSTYPE_MSGCOPY */ + struct { + struct proc *dst; + vir_bytes dst_v; + message msgbuf; + } msgcopy; + } saved; + + /* Parameters of request to VM */ + vir_bytes start, length; /* memory range */ + u8_t writeflag; /* nonzero for write access */ + endpoint_t who; + + /* VM result when available */ + int vmresult; + + /* Target gets this set. (But caller and target can be + * the same, so we can't put this in the 'saved' union.) + */ + struct proc *requestor; + + /* If the suspended operation is a sys_call, its details are + * stored here. + */ + } p_vmrequest; + + struct proc *next_soft_notify; + int p_softnotified; + #if DEBUG_SCHED_CHECK int p_ready, p_found; #endif @@ -59,6 +117,9 @@ struct proc { #define P_STOP 0x40 /* set when process is being traced */ #define NO_PRIV 0x80 /* keep forked system process from running */ #define NO_ENDPOINT 0x100 /* process cannot send or receive messages */ +#define VMINHIBIT 0x200 /* not scheduled until released by VM */ +#define PAGEFAULT 0x400 /* process has unhandled pagefault */ +#define VMREQUEST 0x800 /* originator of vm memory request */ /* These runtime flags can be tested and manipulated by these macros. */ @@ -108,6 +169,7 @@ struct proc { #define REPLY_PENDING 0x01 /* reply to IPC_REQUEST is pending */ #define MF_VM 0x08 /* process uses VM */ #define MF_ASYNMSG 0x10 /* Asynchrous message pending */ +#define MF_FULLVM 0x20 /* Scheduling priorities for p_priority. Values must start at zero (highest * priority) and increment. Priorities of the processes in the boot image diff --git a/kernel/profile.c b/kernel/profile.c index 7e5d6aac8..da0001088 100644 --- a/kernel/profile.c +++ b/kernel/profile.c @@ -98,14 +98,14 @@ irq_hook_t *hook; /* Note: k_reenter is always 0 here. */ /* Store sample (process name and program counter). */ - phys_copy(vir2phys(proc_ptr->p_name), - (phys_bytes) (sprof_data_addr + sprof_info.mem_used), - (phys_bytes) strlen(proc_ptr->p_name)); + data_copy(SYSTEM, (vir_bytes) proc_ptr->p_name, + sprof_ep, sprof_data_addr_vir + sprof_info.mem_used, + strlen(proc_ptr->p_name)); - phys_copy(vir2phys(&proc_ptr->p_reg.pc), - (phys_bytes) (sprof_data_addr+sprof_info.mem_used + + data_copy(SYSTEM, (vir_bytes) &proc_ptr->p_reg.pc, sprof_ep, + (vir_bytes) (sprof_data_addr_vir + sprof_info.mem_used + sizeof(proc_ptr->p_name)), - (phys_bytes) sizeof(proc_ptr->p_reg.pc)); + (vir_bytes) sizeof(proc_ptr->p_reg.pc)); sprof_info.mem_used += sizeof(sprof_sample); @@ -159,26 +159,20 @@ PUBLIC void profile_register(ctl_ptr, tbl_ptr) void *ctl_ptr; void *tbl_ptr; { - int len, proc_nr; + int proc_nr; vir_bytes vir_dst; struct proc *rp; + if(cprof_procs_no >= NR_SYS_PROCS) + return; + /* Store process name, control struct, table locations. */ - proc_nr = KERNEL; - rp = proc_addr(proc_nr); + rp = proc_addr(SYSTEM); cprof_proc_info[cprof_procs_no].endpt = rp->p_endpoint; cprof_proc_info[cprof_procs_no].name = rp->p_name; - - len = (phys_bytes) sizeof (void *); - - vir_dst = (vir_bytes) ctl_ptr; - cprof_proc_info[cprof_procs_no].ctl = - numap_local(proc_nr, vir_dst, len); - - vir_dst = (vir_bytes) tbl_ptr; - cprof_proc_info[cprof_procs_no].buf = - numap_local(proc_nr, vir_dst, len); + cprof_proc_info[cprof_procs_no].ctl_v = (vir_bytes) ctl_ptr; + cprof_proc_info[cprof_procs_no].buf_v = (vir_bytes) tbl_ptr; cprof_procs_no++; } diff --git a/kernel/profile.h b/kernel/profile.h index 048e00c0d..a8c29ed7d 100644 --- a/kernel/profile.h +++ b/kernel/profile.h @@ -10,8 +10,8 @@ EXTERN int sprofiling; /* whether profiling is running */ EXTERN int sprof_mem_size; /* available user memory for data */ EXTERN struct sprof_info_s sprof_info; /* profiling info for user program */ -EXTERN phys_bytes sprof_data_addr; /* user address to write data */ -EXTERN phys_bytes sprof_info_addr; /* user address to write info struct */ +EXTERN vir_bytes sprof_data_addr_vir; /* user address to write data */ +EXTERN endpoint_t sprof_ep; /* user process */ #endif /* SPROFILE */ @@ -20,14 +20,12 @@ EXTERN phys_bytes sprof_info_addr; /* user address to write info struct */ EXTERN int cprof_mem_size; /* available user memory for data */ EXTERN struct cprof_info_s cprof_info; /* profiling info for user program */ -EXTERN phys_bytes cprof_data_addr; /* user address to write data */ -EXTERN phys_bytes cprof_info_addr; /* user address to write info struct */ EXTERN int cprof_procs_no; /* number of profiled processes */ EXTERN struct cprof_proc_info_s { /* info about profiled process */ - int endpt; /* endpoint */ + endpoint_t endpt; /* endpoint */ char *name; /* name */ - phys_bytes ctl; /* location of control struct */ - phys_bytes buf; /* location of buffer */ + vir_bytes ctl_v; /* location of control struct */ + vir_bytes buf_v; /* location of buffer */ int slots_used; /* table slots used */ } cprof_proc_info_inst; EXTERN struct cprof_proc_info_s cprof_proc_info[NR_SYS_PROCS]; diff --git a/kernel/proto.h b/kernel/proto.h index bab60aa33..f8ea886aa 100755 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -5,6 +5,7 @@ #include #include +#include /* Struct declarations. */ struct proc; @@ -20,20 +21,26 @@ _PROTOTYPE( void ser_dump_proc, (void) ); /* main.c */ _PROTOTYPE( void main, (void) ); _PROTOTYPE( void prepare_shutdown, (int how) ); +_PROTOTYPE( void minix_shutdown, (struct timer *tp) ); _PROTOTYPE( void idle_task, (void) ); /* utility.c */ _PROTOTYPE( int kprintf, (const char *fmt, ...) ); -_PROTOTYPE( void panic, (_CONST char *s, int n) ); +_PROTOTYPE( void minix_panic, (char *s, int n) ); /* proc.c */ _PROTOTYPE( int sys_call, (int call_nr, int src_dst, message *m_ptr, long bit_map) ); +_PROTOTYPE( void sys_call_restart, (struct proc *caller) ); _PROTOTYPE( int lock_notify, (int src, int dst) ); +_PROTOTYPE( int soft_notify, (int dst) ); _PROTOTYPE( int lock_send, (int dst, message *m_ptr) ); _PROTOTYPE( void lock_enqueue, (struct proc *rp) ); _PROTOTYPE( void lock_dequeue, (struct proc *rp) ); +_PROTOTYPE( void enqueue, (struct proc *rp) ); +_PROTOTYPE( void dequeue, (struct proc *rp) ); _PROTOTYPE( void balance_queues, (struct timer *tp) ); +_PROTOTYPE( struct proc *endpoint_lookup, (endpoint_t ep) ); #if DEBUG_ENABLE_IPC_WARNINGS _PROTOTYPE( int isokendpt_f, (char *file, int line, endpoint_t e, int *p, int f)); #define isokendpt_d(e, p, f) isokendpt_f(__FILE__, __LINE__, (e), (p), (f)) @@ -52,17 +59,16 @@ _PROTOTYPE( void send_sig, (int proc_nr, int sig_nr) ); _PROTOTYPE( void cause_sig, (int proc_nr, int sig_nr) ); _PROTOTYPE( void sys_task, (void) ); _PROTOTYPE( void get_randomness, (int source) ); -_PROTOTYPE( int virtual_copy, (struct vir_addr *src, struct vir_addr *dst, - vir_bytes bytes) ); #define numap_local(proc_nr, vir_addr, bytes) \ umap_local(proc_addr(proc_nr), D, (vir_addr), (bytes)) _PROTOTYPE( phys_bytes umap_grant, (struct proc *, cp_grant_id_t, vir_bytes)); -_PROTOTYPE( phys_bytes umap_verify_grant, (struct proc *, endpoint_t, - cp_grant_id_t, vir_bytes, vir_bytes, int)); +_PROTOTYPE( vir_bytes vir_verify_grant, (struct proc *, endpoint_t, + cp_grant_id_t, vir_bytes, vir_bytes, int, endpoint_t *)); _PROTOTYPE( void clear_endpoint, (struct proc *rc) ); -_PROTOTYPE( phys_bytes umap_bios, (struct proc *rp, vir_bytes vir_addr, - vir_bytes bytes)); +_PROTOTYPE( phys_bytes umap_bios, (vir_bytes vir_addr, vir_bytes bytes)); +_PROTOTYPE( phys_bytes umap_verify_grant, (struct proc *rp, endpoint_t grantee, cp_grant_id_t grant, vir_bytes offset, vir_bytes bytes, int access)); + /* system/do_newmap.c */ _PROTOTYPE( int newmap, (struct proc *rp, struct mem_map *map_ptr) ); @@ -79,11 +85,11 @@ _PROTOTYPE( void cons_seth, (int pos, int n) ); /* debug.c */ #if DEBUG_SCHED_CHECK -_PROTOTYPE( void check_runqueues, (char *when) ); +#define CHECK_RUNQUEUES check_runqueues_f(__FILE__, __LINE__) +_PROTOTYPE( void check_runqueues_f, (char *file, int line) ); #endif - -/* system/do_vm.c */ -_PROTOTYPE( void vm_map_default, (struct proc *pp) ); +_PROTOTYPE( void timer_start, (int cat, char *name) ); +_PROTOTYPE( void timer_end, (int cat) ); /* system/do_safecopy.c */ _PROTOTYPE( int verify_grant, (endpoint_t, endpoint_t, cp_grant_id_t, vir_bytes, @@ -98,15 +104,27 @@ _PROTOTYPE( void stop_profile_clock, (void) ); /* functions defined in architecture-dependent files. */ _PROTOTYPE( void phys_copy, (phys_bytes source, phys_bytes dest, phys_bytes count) ); +#define virtual_copy(src, dst, bytes) virtual_copy_f(src, dst, bytes, 0) +#define virtual_copy_vmcheck(src, dst, bytes) virtual_copy_f(src, dst, bytes, 1) +_PROTOTYPE( int virtual_copy_f, (struct vir_addr *src, struct vir_addr *dst, + vir_bytes bytes, int vmcheck) ); +_PROTOTYPE( int data_copy, (endpoint_t from, vir_bytes from_addr, + endpoint_t to, vir_bytes to_addr, size_t bytes)); +#define data_copy_to(d, p, v, n) data_copy(SYSTEM, (d), (p), (v), (n)); +#define data_copy_from(d, p, v, n) data_copy((p), (v), SYSTEM, (d), (n)); _PROTOTYPE( void alloc_segments, (struct proc *rp) ); _PROTOTYPE( void vm_init, (void) ); _PROTOTYPE( void vm_map_range, (u32_t base, u32_t size, u32_t offset) ); +_PROTOTYPE( int vm_copy, (vir_bytes src, struct proc *srcproc, + vir_bytes dst, struct proc *dstproc, phys_bytes bytes)); _PROTOTYPE( phys_bytes umap_local, (register struct proc *rp, int seg, vir_bytes vir_addr, vir_bytes bytes)); _PROTOTYPE( void cp_mess, (int src,phys_clicks src_clicks, vir_bytes src_offset, phys_clicks dst_clicks, vir_bytes dst_offset)); _PROTOTYPE( phys_bytes umap_remote, (struct proc* rp, int seg, vir_bytes vir_addr, vir_bytes bytes) ); +_PROTOTYPE( phys_bytes umap_virtual, (struct proc* rp, int seg, + vir_bytes vir_addr, vir_bytes bytes) ); _PROTOTYPE( phys_bytes seg2phys, (U16_t) ); _PROTOTYPE( void phys_memset, (phys_bytes source, unsigned long pattern, phys_bytes count) ); @@ -123,6 +141,7 @@ _PROTOTYPE( void idle_task, (void) ); _PROTOTYPE( void system_init, (void) ); _PROTOTYPE( void ser_putc, (char) ); _PROTOTYPE( void arch_shutdown, (int) ); +_PROTOTYPE( void arch_get_aout_headers, (int i, struct exec *h) ); _PROTOTYPE( void restart, (void) ); _PROTOTYPE( void idle_task, (void) ); _PROTOTYPE( void read_tsc, (unsigned long *high, unsigned long *low) ); @@ -130,5 +149,16 @@ _PROTOTYPE( int arch_init_profile_clock, (u32_t freq) ); _PROTOTYPE( void arch_stop_profile_clock, (void) ); _PROTOTYPE( void arch_ack_profile_clock, (void) ); _PROTOTYPE( void do_ser_debug, (void) ); +_PROTOTYPE( int arch_get_params, (char *parm, int max)); +_PROTOTYPE( int arch_set_params, (char *parm, int max)); +_PROTOTYPE( int arch_pre_exec, (struct proc *pr, u32_t, u32_t)); +_PROTOTYPE( int arch_umap, (struct proc *pr, vir_bytes, vir_bytes, + int, phys_bytes *)); +_PROTOTYPE( int arch_do_vmctl, (message *m_ptr, struct proc *p)); +_PROTOTYPE( int vm_contiguous, (struct proc *targetproc, u32_t vir_buf, size_t count)); +_PROTOTYPE( int vm_checkrange, (struct proc *caller, struct proc *target, + vir_bytes start, vir_bytes length, int writeflag, int checkonly)); +_PROTOTYPE( void proc_stacktrace, (struct proc *proc) ); +_PROTOTYPE( int vm_lookup, (struct proc *proc, vir_bytes virtual, vir_bytes *result, u32_t *ptent)); #endif /* PROTO_H */ diff --git a/kernel/start.c b/kernel/start.c index 4b8fedf85..36b27d585 100755 --- a/kernel/start.c +++ b/kernel/start.c @@ -7,8 +7,6 @@ #include #include -PRIVATE char params[K_PARAM_SIZE]; - FORWARD _PROTOTYPE( char *get_value, (_CONST char *params, _CONST char *key)); /*===========================================================================* * cstart * @@ -21,7 +19,6 @@ U16_t parmoff, parmsize; /* boot parameters offset and length */ /* Perform system initializations prior to calling main(). Most settings are * determined with help of the environment strings passed by MINIX' loader. */ - char params[128*sizeof(char *)]; /* boot monitor parameters */ register char *value; /* value in key=value pair */ extern int etext, end; int h; @@ -36,10 +33,7 @@ U16_t parmoff, parmsize; /* boot parameters offset and length */ system_init(); /* Copy the boot parameters to the local buffer. */ - kinfo.params_base = seg2phys(mds) + parmoff; - kinfo.params_size = MIN(parmsize,sizeof(params)-2); - phys_copy(kinfo.params_base, - vir2phys(params), kinfo.params_size); + arch_get_params(params_buffer, sizeof(params_buffer)); /* Record miscellaneous information for user-space servers. */ kinfo.nr_procs = NR_PROCS; @@ -49,8 +43,6 @@ U16_t parmoff, parmsize; /* boot parameters offset and length */ strncpy(kinfo.version, OS_VERSION, sizeof(kinfo.version)); kinfo.version[sizeof(kinfo.version)-1] = '\0'; kinfo.proc_addr = (vir_bytes) proc; - kinfo.kmem_base = vir2phys(0); - kinfo.kmem_size = (phys_bytes) &end; /* Load average data initialization. */ kloadinfo.proc_last_slot = 0; @@ -58,10 +50,10 @@ U16_t parmoff, parmsize; /* boot parameters offset and length */ kloadinfo.proc_load_history[h] = 0; /* Processor? Decide if mode is protected for older machines. */ - machine.processor=atoi(get_value(params, "processor")); + machine.processor=atoi(get_value(params_buffer, "processor")); /* XT, AT or MCA bus? */ - value = get_value(params, "bus"); + value = get_value(params_buffer, "bus"); if (value == NIL_PTR || strcmp(value, "at") == 0) { machine.pc_at = TRUE; /* PC-AT compatible hardware */ } else if (strcmp(value, "mca") == 0) { @@ -69,7 +61,7 @@ U16_t parmoff, parmsize; /* boot parameters offset and length */ } /* Type of VDU: */ - value = get_value(params, "video"); /* EGA or VGA video unit */ + value = get_value(params_buffer, "video"); /* EGA or VGA video unit */ if (strcmp(value, "ega") == 0) machine.vdu_ega = TRUE; if (strcmp(value, "vga") == 0) machine.vdu_vga = machine.vdu_ega = TRUE; diff --git a/kernel/system.c b/kernel/system.c index 16541711b..e39210757 100755 --- a/kernel/system.c +++ b/kernel/system.c @@ -15,7 +15,6 @@ * send_sig: send a signal directly to a system process * cause_sig: take action to cause a signal to occur via PM * umap_bios: map virtual address in BIOS_SEG to physical - * virtual_copy: copy bytes from one virtual address to another * get_randomness: accumulate randomness in a buffer * clear_endpoint: remove a process' ability to send and receive messages * @@ -31,13 +30,16 @@ #include "kernel.h" #include "system.h" #include "proc.h" +#include "vm.h" #include #include #include +#include #include #include #include #include +#include /* Declaration of the call vector that defines the mapping of system calls * to handler functions. The vector is initialized in sys_init() with map(), @@ -46,12 +48,16 @@ * array size will be negative and this won't compile. */ PUBLIC int (*call_vec[NR_SYS_CALLS])(message *m_ptr); +char *callnames[NR_SYS_CALLS]; #define map(call_nr, handler) \ {extern int dummy[NR_SYS_CALLS>(unsigned)(call_nr-KERNEL_CALL) ? 1:-1];} \ + callnames[(call_nr-KERNEL_CALL)] = #call_nr; \ call_vec[(call_nr-KERNEL_CALL)] = (handler) FORWARD _PROTOTYPE( void initialize, (void)); +FORWARD _PROTOTYPE( void softnotify_check, (void)); +FORWARD _PROTOTYPE( struct proc *vmrestart_check, (message *)); /*===========================================================================* * sys_task * @@ -64,14 +70,39 @@ PUBLIC void sys_task() register struct proc *caller_ptr; int s; int call_nr; + int n = 0; /* Initialize the system task. */ initialize(); while (TRUE) { - int r; - /* Get work. Block and wait until a request message arrives. */ - if((r=receive(ANY, &m)) != OK) panic("system: receive() failed", r); + struct proc *restarting; + +#if 0 +if(!(n++ % 100000)) { + int i; + kprintf("switch %8d reload %8d\n", cr3switch, cr3reload); +} +#endif + + restarting = vmrestart_check(&m); + softnotify_check(); + if(softnotify) + minix_panic("softnotify non-NULL before receive (1)", NO_NUM); + + if(!restarting) { + int r; + /* Get work. Block and wait until a request message arrives. */ + if(softnotify) + minix_panic("softnotify non-NULL before receive (2)", NO_NUM); + if((r=receive(ANY, &m)) != OK) + minix_panic("receive() failed", r); + if(m.m_source == SYSTEM) + continue; + if(softnotify) + minix_panic("softnotify non-NULL after receive", NO_NUM); + } + sys_call_code = (unsigned) m.m_type; call_nr = sys_call_code - KERNEL_CALL; who_e = m.m_source; @@ -115,16 +146,34 @@ PUBLIC void sys_task() result = (*call_vec[call_nr])(&m); /* handle the system call */ } - /* Send a reply, unless inhibited by a handler function. Use the kernel - * function lock_send() to prevent a system call trap. The destination - * is known to be blocked waiting for a message. - */ - if (result != EDONTREPLY) { - m.m_type = result; /* report status of call */ - if (OK != (s=lock_send(m.m_source, &m))) { - kprintf("SYSTEM, reply to %d failed: %d\n", m.m_source, s); - } - } + if(result == VMSUSPEND) { + /* Special case: message has to be saved for handling + * until VM tells us it's allowed. VM has been notified + * and we must wait for its reply to restart the call. + */ + memcpy(&caller_ptr->p_vmrequest.saved.reqmsg, &m, sizeof(m)); + caller_ptr->p_vmrequest.type = VMSTYPE_SYS_MESSAGE; +#if 0 + kprintf("SYSTEM: suspending call from %d\n", m.m_source); +#endif + } else if (result != EDONTREPLY) { + /* Send a reply, unless inhibited by a handler function. + * Use the kernel function lock_send() to prevent a system + * call trap. + */ + if(restarting) + RTS_LOCK_UNSET(restarting, VMREQUEST); + m.m_type = result; /* report status of call */ + if(WILLRECEIVE(caller_ptr, SYSTEM)) { + if (OK != (s=lock_send(m.m_source, &m))) { + kprintf("SYSTEM, reply to %d failed: %d\n", + m.m_source, s); + } + } else { + kprintf("SYSTEM: not replying to %d; not ready\n", + caller_ptr->p_endpoint); + } + } } } @@ -153,6 +202,7 @@ PRIVATE void initialize(void) */ for (i=0; is_sig_pending, sig_nr); - lock_notify(SYSTEM, rp->p_endpoint); + soft_notify(rp->p_endpoint); } /*===========================================================================* @@ -317,7 +364,7 @@ int sig_nr; /* signal to be sent, 1 to _NSIG */ register struct proc *rp; if (proc_nr == PM_PROC_NR) - panic("cause_sig: PM gets signal", NO_NUM); + minix_panic("cause_sig: PM gets signal", NO_NUM); /* Check if the signal is already pending. Process it otherwise. */ rp = proc_addr(proc_nr); @@ -335,8 +382,7 @@ int sig_nr; /* signal to be sent, 1 to _NSIG */ /*===========================================================================* * umap_bios * *===========================================================================*/ -PUBLIC phys_bytes umap_bios(rp, vir_addr, bytes) -register struct proc *rp; /* pointer to proc table entry for process */ +PUBLIC phys_bytes umap_bios(vir_addr, bytes) vir_bytes vir_addr; /* virtual address in BIOS segment */ vir_bytes bytes; /* # of bytes to be copied */ { @@ -358,37 +404,6 @@ vir_bytes bytes; /* # of bytes to be copied */ } #endif -/*===========================================================================* - * umap_verify_grant * - *===========================================================================*/ -PUBLIC phys_bytes umap_verify_grant(rp, grantee, grant, offset, bytes, access) -struct proc *rp; /* pointer to proc table entry for process */ -endpoint_t grantee; /* who wants to do this */ -cp_grant_id_t grant; /* grant no. */ -vir_bytes offset; /* offset into grant */ -vir_bytes bytes; /* size */ -int access; /* does grantee want to CPF_READ or _WRITE? */ -{ - int proc_nr; - vir_bytes v_offset; - endpoint_t granter; - - /* See if the grant in that process is sensible, and - * find out the virtual address and (optionally) new - * process for that address. - * - * Then convert that process to a slot number. - */ - if(verify_grant(rp->p_endpoint, grantee, grant, bytes, access, offset, - &v_offset, &granter) != OK - || !isokendpt(granter, &proc_nr)) { - return 0; - } - - /* Do the mapping from virtual to physical. */ - return umap_local(proc_addr(proc_nr), D, v_offset, bytes); -} - /*===========================================================================* * umap_grant * *===========================================================================*/ @@ -398,9 +413,9 @@ cp_grant_id_t grant; /* grant no. */ vir_bytes bytes; /* size */ { int proc_nr; - vir_bytes offset; + vir_bytes offset, ret; endpoint_t granter; - + /* See if the grant in that process is sensible, and * find out the virtual address and (optionally) new * process for that address. @@ -409,88 +424,25 @@ vir_bytes bytes; /* size */ */ if(verify_grant(rp->p_endpoint, ANY, grant, bytes, 0, 0, &offset, &granter) != OK) { + kprintf("SYSTEM: umap_grant: verify_grant failed\n"); return 0; } if(!isokendpt(granter, &proc_nr)) { + kprintf("SYSTEM: umap_grant: isokendpt failed\n"); return 0; } /* Do the mapping from virtual to physical. */ - return umap_local(proc_addr(proc_nr), D, offset, bytes); + ret = umap_virtual(proc_addr(proc_nr), D, offset, bytes); + if(!ret) { + kprintf("SYSTEM:umap_grant:umap_virtual failed; grant %s:%d -> %s: vir 0x%lx\n", + rp->p_name, grant, + proc_addr(proc_nr)->p_name, offset); + } + return ret; } -/*===========================================================================* - * virtual_copy * - *===========================================================================*/ -PUBLIC int virtual_copy(src_addr, dst_addr, bytes) -struct vir_addr *src_addr; /* source virtual address */ -struct vir_addr *dst_addr; /* destination virtual address */ -vir_bytes bytes; /* # of bytes to copy */ -{ -/* Copy bytes from virtual address src_addr to virtual address dst_addr. - * Virtual addresses can be in ABS, LOCAL_SEG, REMOTE_SEG, or BIOS_SEG. - */ - struct vir_addr *vir_addr[2]; /* virtual source and destination address */ - phys_bytes phys_addr[2]; /* absolute source and destination */ - int seg_index; - int i; - - /* Check copy count. */ - if (bytes <= 0) return(EDOM); - - /* Do some more checks and map virtual addresses to physical addresses. */ - vir_addr[_SRC_] = src_addr; - vir_addr[_DST_] = dst_addr; - for (i=_SRC_; i<=_DST_; i++) { - int proc_nr, type; - struct proc *p; - - type = vir_addr[i]->segment & SEGMENT_TYPE; - if(type != PHYS_SEG && isokendpt(vir_addr[i]->proc_nr_e, &proc_nr)) - p = proc_addr(proc_nr); - else - p = NULL; - - /* Get physical address. */ - switch(type) { - case LOCAL_SEG: - if(!p) return EDEADSRCDST; - seg_index = vir_addr[i]->segment & SEGMENT_INDEX; - phys_addr[i] = umap_local(p, seg_index, vir_addr[i]->offset, bytes); - break; - case REMOTE_SEG: - if(!p) return EDEADSRCDST; - seg_index = vir_addr[i]->segment & SEGMENT_INDEX; - phys_addr[i] = umap_remote(p, seg_index, vir_addr[i]->offset, bytes); - break; -#if _MINIX_CHIP == _CHIP_INTEL - case BIOS_SEG: - if(!p) return EDEADSRCDST; - phys_addr[i] = umap_bios(p, vir_addr[i]->offset, bytes ); - break; -#endif - case PHYS_SEG: - phys_addr[i] = vir_addr[i]->offset; - break; - case GRANT_SEG: - phys_addr[i] = umap_grant(p, vir_addr[i]->offset, bytes); - break; - default: - return(EINVAL); - } - - /* Check if mapping succeeded. */ - if (phys_addr[i] <= 0 && vir_addr[i]->segment != PHYS_SEG) - return(EFAULT); - } - - /* Now copy bytes between physical addresseses. */ - phys_copy(phys_addr[_SRC_], phys_addr[_DST_], (phys_bytes) bytes); - return(OK); -} - - /*===========================================================================* * clear_endpoint * *===========================================================================*/ @@ -499,8 +451,22 @@ register struct proc *rc; /* slot of process to clean up */ { register struct proc *rp; /* iterate over process table */ register struct proc **xpp; /* iterate over caller queue */ + struct proc *np; - if(isemptyp(rc)) panic("clear_proc: empty process", proc_nr(rc)); + if(isemptyp(rc)) minix_panic("clear_proc: empty process", proc_nr(rc)); + +#if 1 + if(rc->p_endpoint == PM_PROC_NR || rc->p_endpoint == VFS_PROC_NR) { + /* This test is great for debugging system processes dying, + * but as this happens normally on reboot, not good permanent code. + */ + kprintf("process %s / %d died; stack: ", rc->p_name, rc->p_endpoint); + proc_stacktrace(rc); + kprintf("kernel trace: "); + util_stacktrace(); + minix_panic("clear_proc: system process died", rc->p_endpoint); + } +#endif /* Make sure that the exiting process is no longer scheduled. */ RTS_LOCK_SET(rc, NO_ENDPOINT); @@ -550,7 +516,8 @@ register struct proc *rc; /* slot of process to clean up */ rp->p_reg.retreg = ESRCDIED; /* report source died */ RTS_LOCK_UNSET(rp, RECEIVING); /* no longer receiving */ #if DEBUG_ENABLE_IPC_WARNINGS - kprintf("Proc %d receive dead src %d\n", proc_nr(rp), proc_nr(rc)); + kprintf("Proc %d (%s) receiving from dead src %d (%s)\n", + proc_nr(rp), rp->p_name, proc_nr(rc), rc->p_name); #endif } if (RTS_ISSET(rp, SENDING) && @@ -558,8 +525,147 @@ register struct proc *rc; /* slot of process to clean up */ rp->p_reg.retreg = EDSTDIED; /* report destination died */ RTS_LOCK_UNSET(rp, SENDING); #if DEBUG_ENABLE_IPC_WARNINGS - kprintf("Proc %d send dead dst %d\n", proc_nr(rp), proc_nr(rc)); + kprintf("Proc %d (%s) send to dying dst %d (%s)\n", + proc_nr(rp), rp->p_name, proc_nr(rc), rc->p_name); #endif } } + + /* No pending soft notifies. */ + for(np = softnotify; np; np = np->next_soft_notify) { + if(np == rc) { + minix_panic("dying proc was on next_soft_notify", np->p_endpoint); + } + } +} + +/*===========================================================================* + * umap_verify_grant * + *===========================================================================*/ +PUBLIC phys_bytes umap_verify_grant(rp, grantee, grant, offset, bytes, access) +struct proc *rp; /* pointer to proc table entry for process */ +endpoint_t grantee; /* who wants to do this */ +cp_grant_id_t grant; /* grant no. */ +vir_bytes offset; /* offset into grant */ +vir_bytes bytes; /* size */ +int access; /* does grantee want to CPF_READ or _WRITE? */ +{ + int proc_nr; + vir_bytes v_offset; + endpoint_t granter; + + /* See if the grant in that process is sensible, and + * find out the virtual address and (optionally) new + * process for that address. + * + * Then convert that process to a slot number. + */ + if(verify_grant(rp->p_endpoint, grantee, grant, bytes, access, offset, + &v_offset, &granter) != OK + || !isokendpt(granter, &proc_nr)) { + return 0; + } + + /* Do the mapping from virtual to physical. */ + return umap_virtual(proc_addr(proc_nr), D, v_offset, bytes); +} + +/*===========================================================================* + * softnotify_check * + *===========================================================================*/ +PRIVATE void softnotify_check(void) +{ + struct proc *np, *nextnp; + + if(!softnotify) + return; + + for(np = softnotify; np; np = nextnp) { + if(!np->p_softnotified) + minix_panic("softnotify but no p_softnotified", NO_NUM); + lock_notify(SYSTEM, np->p_endpoint); + nextnp = np->next_soft_notify; + np->next_soft_notify = NULL; + np->p_softnotified = 0; + } + + softnotify = NULL; +} + +/*===========================================================================* + * vmrestart_check * + *===========================================================================*/ +PRIVATE struct proc *vmrestart_check(message *m) +{ + int type, r; + struct proc *restarting; + + /* Anyone waiting to be vm-restarted? */ + + if(!(restarting = vmrestart)) + return NULL; + + if(restarting->p_rts_flags & SLOT_FREE) + minix_panic("SYSTEM: VMREQUEST set for empty process", NO_NUM); + + type = restarting->p_vmrequest.type; + restarting->p_vmrequest.type = VMSTYPE_SYS_NONE; + vmrestart = restarting->p_vmrequest.nextrestart; + + if(!RTS_ISSET(restarting, VMREQUEST)) + minix_panic("SYSTEM: VMREQUEST not set for process on vmrestart queue", + restarting->p_endpoint); + + switch(type) { + case VMSTYPE_SYS_MESSAGE: + memcpy(m, &restarting->p_vmrequest.saved.reqmsg, sizeof(*m)); +#if 0 + kprintf("SYSTEM: restart sys_message type %d / %lx source %d\n", + m->m_type, m->m_type, m->m_source); +#endif + if(m->m_source != restarting->p_endpoint) + minix_panic("SYSTEM: vmrestart source doesn't match", + NO_NUM); + /* Original caller could've disappeared in the meantime. */ + if(!isokendpt(m->m_source, &who_p)) { + kprintf("SYSTEM: ignoring call %d from dead %d\n", + m->m_type, m->m_source); + return NULL; + } + { int i; + i = m->m_type - KERNEL_CALL; + if(i >= 0 && i < NR_SYS_CALLS) { +#if 0 + kprintf("SYSTEM: restart %s from %d\n", + callnames[i], m->m_source); +#endif + } else { + minix_panic("call number out of range", i); + } + } + return restarting; + case VMSTYPE_SYS_CALL: + kprintf("SYSTEM: restart sys_call\n"); + /* Restarting a kernel trap. */ + sys_call_restart(restarting); + + /* Handled; restart system loop. */ + return NULL; + case VMSTYPE_MSGCOPY: + /* Do delayed message copy. */ + if((r=data_copy(SYSTEM, + (vir_bytes) &restarting->p_vmrequest.saved.msgcopy.msgbuf, + restarting->p_vmrequest.saved.msgcopy.dst->p_endpoint, + (vir_bytes) restarting->p_vmrequest.saved.msgcopy.dst_v, + sizeof(message))) != OK) { + minix_panic("SYSTEM: delayed msgcopy failed", r); + } + RTS_LOCK_UNSET(restarting, VMREQUEST); + + /* Handled; restart system loop. */ + return NULL; + default: + minix_panic("strange restart type", type); + } + minix_panic("fell out of switch", NO_NUM); } diff --git a/kernel/system.h b/kernel/system.h index 0cf60fa7d..3f187ca70 100644 --- a/kernel/system.h +++ b/kernel/system.h @@ -71,14 +71,12 @@ _PROTOTYPE( int do_nice, (message *m_ptr) ); _PROTOTYPE( int do_copy, (message *m_ptr) ); #define do_vircopy do_copy -#define do_physcopy do_copy #if ! (USE_VIRCOPY || USE_PHYSCOPY) #define do_copy do_unused #endif _PROTOTYPE( int do_vcopy, (message *m_ptr) ); #define do_virvcopy do_vcopy -#define do_physvcopy do_vcopy #if ! (USE_VIRVCOPY || USE_PHYSVCOPY) #define do_vcopy do_unused #endif @@ -178,8 +176,10 @@ _PROTOTYPE( int do_stime, (message *m_ptr) ); _PROTOTYPE( int do_safecopy, (message *m_ptr) ); _PROTOTYPE( int do_vsafecopy, (message *m_ptr) ); _PROTOTYPE( int do_iopenable, (message *m_ptr) ); +_PROTOTYPE( int do_vmctl, (message *m_ptr) ); _PROTOTYPE( int do_setgrant, (message *m_ptr) ); _PROTOTYPE( int do_readbios, (message *m_ptr) ); +_PROTOTYPE( int do_mapdma, (message *m_ptr) ); _PROTOTYPE( int do_sprofile, (message *m_ptr) ); #if ! SPROFILE diff --git a/kernel/system/Makefile b/kernel/system/Makefile index c6a4a0f66..6f65a6407 100644 --- a/kernel/system/Makefile +++ b/kernel/system/Makefile @@ -50,12 +50,12 @@ OBJECTS = \ $(SYSTEM)(do_sigreturn.o) \ $(SYSTEM)(do_abort.o) \ $(SYSTEM)(do_getinfo.o) \ - $(SYSTEM)(do_vm.o) \ $(SYSTEM)(do_vm_setbuf.o) \ $(SYSTEM)(do_sprofile.o) \ $(SYSTEM)(do_cprofile.o) \ $(SYSTEM)(do_profbuf.o) \ - $(SYSTEM)(do_mapdma.o) + $(SYSTEM)(do_mapdma.o) \ + $(SYSTEM)(do_vmctl.o) build $(SYSTEM): $(OBJECTS) aal cr $@ *.o @@ -172,3 +172,6 @@ $(SYSTEM)(do_profbuf.o): do_profbuf.c $(SYSTEM)(do_mapdma.o): do_mapdma.c $(CC) do_mapdma.c + +$(SYSTEM)(do_vmctl.o): do_vmctl.c + $(CC) do_vmctl.c diff --git a/kernel/system/do_abort.c b/kernel/system/do_abort.c index d0b32b516..9223dfe39 100644 --- a/kernel/system/do_abort.c +++ b/kernel/system/do_abort.c @@ -23,21 +23,25 @@ message *m_ptr; /* pointer to request message */ * in the PM (normal abort or panic) or TTY (after CTRL-ALT-DEL). */ int how = m_ptr->ABRT_HOW; - int proc_nr; int length; phys_bytes src_phys; /* See if the monitor is to run the specified instructions. */ if (how == RBT_MONITOR) { + int p; + static char paramsbuffer[512]; + int len; + len = MIN(m_ptr->ABRT_MON_LEN, sizeof(paramsbuffer)-1); - if(!isokendpt(m_ptr->ABRT_MON_ENDPT, &proc_nr)) return(EDEADSRCDST); - length = m_ptr->ABRT_MON_LEN + 1; - if (length > kinfo.params_size) return(E2BIG); - src_phys = numap_local(proc_nr,(vir_bytes)m_ptr->ABRT_MON_ADDR,length); - if (! src_phys) return(EFAULT); + if((p=data_copy(m_ptr->ABRT_MON_ENDPT, (vir_bytes) m_ptr->ABRT_MON_ADDR, + SYSTEM, (vir_bytes) paramsbuffer, len)) != OK) { + return p; + } + paramsbuffer[len] = '\0'; /* Parameters seem ok, copy them and prepare shutting down. */ - phys_copy(src_phys, kinfo.params_base, (phys_bytes) length); + if((p = arch_set_params(paramsbuffer, len+1)) != OK) + return p; } /* Now prepare to shutdown MINIX. */ diff --git a/kernel/system/do_copy.c b/kernel/system/do_copy.c index 716ec1a85..93df4b7f1 100644 --- a/kernel/system/do_copy.c +++ b/kernel/system/do_copy.c @@ -12,6 +12,7 @@ */ #include "../system.h" +#include "../vm.h" #include #if (USE_VIRCOPY || USE_PHYSCOPY) @@ -30,8 +31,9 @@ register message *m_ptr; /* pointer to request message */ phys_bytes bytes; /* number of bytes to copy */ int i; - if (m_ptr->m_source != 0 && m_ptr->m_source != 1 && - m_ptr->m_source != 2 && m_ptr->m_source != 3) + if (m_ptr->m_source != PM_PROC_NR && m_ptr->m_source != VFS_PROC_NR && + m_ptr->m_source != RS_PROC_NR && m_ptr->m_source != MEM_PROC_NR && + m_ptr->m_source != VM_PROC_NR) { static int first=1; if (first) @@ -64,9 +66,13 @@ register message *m_ptr; /* pointer to request message */ /* Check if process number was given implictly with SELF and is valid. */ if (vir_addr[i].proc_nr_e == SELF) vir_addr[i].proc_nr_e = m_ptr->m_source; - if (vir_addr[i].segment != PHYS_SEG && - ! isokendpt(vir_addr[i].proc_nr_e, &p)) + if (vir_addr[i].segment != PHYS_SEG) { + if(! isokendpt(vir_addr[i].proc_nr_e, &p)) { + kprintf("do_copy: %d: seg 0x%x, %d not ok endpoint\n", + i, vir_addr[i].segment, vir_addr[i].proc_nr_e); return(EINVAL); + } + } /* Check if physical addressing is used without SYS_PHYSCOPY. */ if ((vir_addr[i].segment & PHYS_SEG) && @@ -79,7 +85,7 @@ register message *m_ptr; /* pointer to request message */ if (bytes != (vir_bytes) bytes) return(E2BIG); /* Now try to make the actual virtual copy. */ - return( virtual_copy(&vir_addr[_SRC_], &vir_addr[_DST_], bytes) ); + return( virtual_copy_vmcheck(&vir_addr[_SRC_], &vir_addr[_DST_], bytes) ); } #endif /* (USE_VIRCOPY || USE_PHYSCOPY) */ diff --git a/kernel/system/do_cprofile.c b/kernel/system/do_cprofile.c index 506373049..f247311d4 100644 --- a/kernel/system/do_cprofile.c +++ b/kernel/system/do_cprofile.c @@ -25,8 +25,8 @@ PUBLIC int do_cprofile(m_ptr) register message *m_ptr; /* pointer to request message */ { int proc_nr, i, err = 0, k = 0; - vir_bytes vir_dst; - phys_bytes phys_src, phys_dst, len; + phys_bytes len; + vir_bytes vir_dst, vir_src; switch (m_ptr->PROF_ACTION) { @@ -50,10 +50,9 @@ register message *m_ptr; /* pointer to request message */ } /* Set reset flag. */ - phys_src = vir2phys((vir_bytes) &cprof_ctl_inst.reset); - phys_dst = (phys_bytes) cprof_proc_info[i].ctl; - len = (phys_bytes) sizeof(cprof_ctl_inst.reset); - phys_copy(phys_src, phys_dst, len); + data_copy(SYSTEM, (vir_bytes) &cprof_ctl_inst.reset, + cprof_proc_info[i].endpt, cprof_proc_info[i].ctl_v, + sizeof(cprof_ctl_inst.reset)); } kprintf("\n"); @@ -71,14 +70,6 @@ register message *m_ptr; /* pointer to request message */ if(!isokendpt(m_ptr->PROF_ENDPT, &proc_nr)) return EINVAL; - vir_dst = (vir_bytes) m_ptr->PROF_CTL_PTR; - len = (phys_bytes) sizeof (int *); - cprof_info_addr = numap_local(proc_nr, vir_dst, len); - - vir_dst = (vir_bytes) m_ptr->PROF_MEM_PTR; - len = (phys_bytes) sizeof (char *); - cprof_data_addr = numap_local(proc_nr, vir_dst, len); - cprof_mem_size = m_ptr->PROF_MEM_SIZE; kprintf("CPROFILE notice: getting tables:"); @@ -101,10 +92,9 @@ register message *m_ptr; /* pointer to request message */ } /* Copy control struct from proc to local variable. */ - phys_src = cprof_proc_info[i].ctl; - phys_dst = vir2phys((vir_bytes) &cprof_ctl_inst); - len = (phys_bytes) sizeof(cprof_ctl_inst); - phys_copy(phys_src, phys_dst, len); + data_copy(cprof_proc_info[i].endpt, cprof_proc_info[i].ctl_v, + SYSTEM, (vir_bytes) &cprof_ctl_inst, + sizeof(cprof_ctl_inst)); /* Calculate memory used. */ cprof_proc_info[i].slots_used = cprof_ctl_inst.slots_used; @@ -121,32 +111,33 @@ register message *m_ptr; /* pointer to request message */ if (cprof_mem_size < cprof_info.mem_used) cprof_info.mem_used = -1; /* Copy the info struct to the user process. */ - phys_copy(vir2phys((vir_bytes) &cprof_info), cprof_info_addr, - (phys_bytes) sizeof(cprof_info)); + data_copy(SYSTEM, (vir_bytes) &cprof_info, + m_ptr->PROF_ENDPT, (vir_bytes) m_ptr->PROF_CTL_PTR, + sizeof(cprof_info)); /* If there is no space or errors occurred, don't bother copying. */ if (cprof_info.mem_used == -1 || cprof_info.err) return OK; /* For each profiled process, copy its name, slots_used and profiling * table to the user process. */ - phys_dst = cprof_data_addr; + vir_dst = (vir_bytes) m_ptr->PROF_MEM_PTR; for (i=0; iPROF_ENDPT, vir_dst, len); + vir_dst += CPROF_PROCNAME_LEN; - phys_src = cprof_proc_info[i].ctl + - sizeof(cprof_ctl_inst.reset); len = (phys_bytes) sizeof(cprof_ctl_inst.slots_used); - phys_copy(phys_src, phys_dst, len); - phys_dst += len; + data_copy(cprof_proc_info[i].endpt, + cprof_proc_info[i].ctl_v + sizeof(cprof_ctl_inst.reset), + m_ptr->PROF_ENDPT, vir_dst, len); + vir_dst += len; - phys_src = cprof_proc_info[i].buf; len = (phys_bytes) (sizeof(cprof_tbl_inst) * cprof_proc_info[i].slots_used); - phys_copy(phys_src, phys_dst, len); - phys_dst += len; + data_copy(cprof_proc_info[i].endpt, cprof_proc_info[i].buf_v, + m_ptr->PROF_ENDPT, vir_dst, len); + vir_dst += len; } return OK; diff --git a/kernel/system/do_devio.c b/kernel/system/do_devio.c index c9ef7a855..ee7e0a912 100644 --- a/kernel/system/do_devio.c +++ b/kernel/system/do_devio.c @@ -110,9 +110,9 @@ doit: } } else { switch (io_type) { - case _DIO_BYTE: outb(m_ptr->DIO_PORT, m_ptr->DIO_VALUE); break; - case _DIO_WORD: outw(m_ptr->DIO_PORT, m_ptr->DIO_VALUE); break; - case _DIO_LONG: outl(m_ptr->DIO_PORT, m_ptr->DIO_VALUE); break; + case _DIO_BYTE: outb(m_ptr->DIO_PORT, m_ptr->DIO_VALUE); break; + case _DIO_WORD: outw(m_ptr->DIO_PORT, m_ptr->DIO_VALUE); break; + case _DIO_LONG: outl(m_ptr->DIO_PORT, m_ptr->DIO_VALUE); break; default: return(EINVAL); } } diff --git a/kernel/system/do_exec.c b/kernel/system/do_exec.c index dca66d9c1..1fbdd0b0f 100644 --- a/kernel/system/do_exec.c +++ b/kernel/system/do_exec.c @@ -22,7 +22,6 @@ register message *m_ptr; /* pointer to request message */ { /* Handle sys_exec(). A process has done a successful EXEC. Patch it up. */ register struct proc *rp; - reg_t sp; /* new sp */ phys_bytes phys_name; char *np; int proc; @@ -31,27 +30,18 @@ register message *m_ptr; /* pointer to request message */ return EINVAL; rp = proc_addr(proc); - sp = (reg_t) m_ptr->PR_STACK_PTR; - rp->p_reg.sp = sp; /* set the stack pointer */ - -#if (_MINIX_CHIP == _CHIP_INTEL) - /* wipe extra LDT entries */ - phys_memset(vir2phys(&rp->p_seg.p_ldt[EXTRA_LDT_INDEX]), 0, - (LDT_SIZE - EXTRA_LDT_INDEX) * sizeof(rp->p_seg.p_ldt[0])); -#endif - rp->p_reg.pc = (reg_t) m_ptr->PR_IP_PTR; /* set pc */ - RTS_LOCK_UNSET(rp, RECEIVING); /* PM does not reply to EXEC call */ + /* Save command name for debugging, ps(1) output, etc. */ - phys_name = numap_local(who_p, (vir_bytes) m_ptr->PR_NAME_PTR, - (vir_bytes) P_NAME_LEN - 1); - if (phys_name != 0) { - phys_copy(phys_name, vir2phys(rp->p_name), (phys_bytes) P_NAME_LEN - 1); - for (np = rp->p_name; (*np & BYTE) >= ' '; np++) {} - *np = 0; /* mark end */ - } else { + if(data_copy(who_e, (vir_bytes) m_ptr->PR_NAME_PTR, + SYSTEM, (vir_bytes) rp->p_name, (phys_bytes) P_NAME_LEN - 1) != OK) strncpy(rp->p_name, "", P_NAME_LEN); - } - + + /* Do architecture-specific exec() stuff. */ + arch_pre_exec(rp, (u32_t) m_ptr->PR_IP_PTR, (u32_t) m_ptr->PR_STACK_PTR); + + /* No reply to EXEC call */ + RTS_LOCK_UNSET(rp, RECEIVING); + return(OK); } #endif /* USE_EXEC */ diff --git a/kernel/system/do_exit.c b/kernel/system/do_exit.c index 99d6d6c68..543f3f8f4 100644 --- a/kernel/system/do_exit.c +++ b/kernel/system/do_exit.c @@ -56,9 +56,11 @@ register struct proc *rc; /* slot of process to clean up */ /* Don't clear if already cleared. */ if(isemptyp(rc)) return; + /* Remove the process' ability to send and receive messages */ clear_endpoint(rc); + /* Turn off any alarm timers at the clock. */ reset_timer(&priv(rc)->s_alarm_timer); @@ -70,10 +72,10 @@ register struct proc *rc; /* slot of process to clean up */ /* Check the table with IRQ hooks to see if hooks should be released. */ for (i=0; i < NR_IRQ_HOOKS; i++) { int proc; - if (rc->p_endpoint == irq_hooks[i].proc_nr_e) { + if (rc->p_endpoint == irq_hooks[i].proc_nr_e) { rm_irq_handler(&irq_hooks[i]); /* remove interrupt handler */ irq_hooks[i].proc_nr_e = NONE; /* mark hook as free */ - } + } } /* Release the process table slot. If this is a system process, also @@ -83,9 +85,12 @@ register struct proc *rc; /* slot of process to clean up */ */ if (priv(rc)->s_flags & SYS_PROC) priv(rc)->s_proc_nr = NONE; +#if 0 /* Clean up virtual memory */ - if (rc->p_misc_flags & MF_VM) + if (rc->p_misc_flags & MF_VM) { vm_map_default(rc); + } +#endif } #endif /* USE_EXIT */ diff --git a/kernel/system/do_fork.c b/kernel/system/do_fork.c index 63016e146..7e6b30388 100644 --- a/kernel/system/do_fork.c +++ b/kernel/system/do_fork.c @@ -41,10 +41,10 @@ register message *m_ptr; /* pointer to request message */ gen = _ENDPOINT_G(rpc->p_endpoint); #if (_MINIX_CHIP == _CHIP_INTEL) old_ldt_sel = rpc->p_seg.p_ldt_sel; /* backup local descriptors */ +#endif *rpc = *rpp; /* copy 'proc' struct */ +#if (_MINIX_CHIP == _CHIP_INTEL) rpc->p_seg.p_ldt_sel = old_ldt_sel; /* restore descriptors */ -#else - *rpc = *rpp; /* copy 'proc' struct */ #endif if(++gen >= _ENDPOINT_MAX_GENERATION) /* increase generation */ gen = 1; /* generation number wraparound */ @@ -77,6 +77,11 @@ register message *m_ptr; /* pointer to request message */ /* Install new map */ r = newmap(rpc, map_ptr); + /* Don't schedule process in VM mode until it has a new pagetable. */ + if(m_ptr->PR_FORK_FLAGS & PFF_VMINHIBIT) { + RTS_LOCK_SET(rpc, VMINHIBIT); + } + /* Only one in group should have SIGNALED, child doesn't inherit tracing. */ RTS_LOCK_UNSET(rpc, (SIGNALED | SIG_PENDING | P_STOP)); sigemptyset(&rpc->p_pending); diff --git a/kernel/system/do_getinfo.c b/kernel/system/do_getinfo.c index d51e227ae..433e49fc0 100644 --- a/kernel/system/do_getinfo.c +++ b/kernel/system/do_getinfo.c @@ -10,13 +10,7 @@ */ #include "../system.h" - -#if !( POWERPC ) - -static unsigned long bios_buf[1024]; /* 4K, what about alignment */ -static vir_bytes bios_buf_vir, bios_buf_len; - -#endif /* #if !( POWERPC ) */ +#include "../vm.h" #if USE_GETINFO @@ -31,35 +25,44 @@ register message *m_ptr; /* pointer to request message */ * call simply copies entire data structures to the caller. */ size_t length; - phys_bytes src_phys; - phys_bytes dst_phys; - int proc_nr, nr_e, nr; + vir_bytes src_vir; + int proc_nr, nr_e, nr, hz; + struct proc *caller; + phys_bytes ph; + + caller = proc_addr(who_p); /* Set source address and length based on request type. */ switch (m_ptr->I_REQUEST) { case GET_MACHINE: { length = sizeof(struct machine); - src_phys = vir2phys(&machine); + src_vir = (vir_bytes) &machine; break; } case GET_KINFO: { length = sizeof(struct kinfo); - src_phys = vir2phys(&kinfo); + src_vir = (vir_bytes) &kinfo; break; } case GET_LOADINFO: { length = sizeof(struct loadinfo); - src_phys = vir2phys(&kloadinfo); + src_vir = (vir_bytes) &kloadinfo; + break; + } + case GET_HZ: { + length = sizeof(hz); + src_vir = (vir_bytes) &hz; + hz = HZ; break; } case GET_IMAGE: { length = sizeof(struct boot_image) * NR_BOOT_PROCS; - src_phys = vir2phys(image); + src_vir = (vir_bytes) image; break; } case GET_IRQHOOKS: { length = sizeof(struct irq_hook) * NR_IRQ_HOOKS; - src_phys = vir2phys(irq_hooks); + src_vir = (vir_bytes) irq_hooks; break; } case GET_SCHEDINFO: { @@ -67,36 +70,44 @@ register message *m_ptr; /* pointer to request message */ * at once, otherwise the scheduling information may be incorrect. * Copy the queue heads and fall through to copy the process table. */ + if((ph=umap_local(caller, D, (vir_bytes) m_ptr->I_VAL_PTR2,length)) == 0) + return EFAULT; length = sizeof(struct proc *) * NR_SCHED_QUEUES; - src_phys = vir2phys(rdy_head); - okendpt(m_ptr->m_source, &proc_nr); - dst_phys = numap_local(proc_nr, (vir_bytes) m_ptr->I_VAL_PTR2, - length); - if (src_phys == 0 || dst_phys == 0) return(EFAULT); - phys_copy(src_phys, dst_phys, length); - /* fall through */ + CHECKRANGE_OR_SUSPEND(proc_addr(who_p), ph, length, 1); + data_copy(SYSTEM, (vir_bytes) rdy_head, + who_e, (vir_bytes) m_ptr->I_VAL_PTR2, length); + /* fall through to GET_PROCTAB */ } case GET_PROCTAB: { length = sizeof(struct proc) * (NR_PROCS + NR_TASKS); - src_phys = vir2phys(proc); + src_vir = (vir_bytes) proc; break; } case GET_PRIVTAB: { length = sizeof(struct priv) * (NR_SYS_PROCS); - src_phys = vir2phys(priv); + src_vir = (vir_bytes) priv; break; } case GET_PROC: { nr_e = (m_ptr->I_VAL_LEN2_E == SELF) ? - m_ptr->m_source : m_ptr->I_VAL_LEN2_E; + who_e : m_ptr->I_VAL_LEN2_E; if(!isokendpt(nr_e, &nr)) return EINVAL; /* validate request */ length = sizeof(struct proc); - src_phys = vir2phys(proc_addr(nr)); + src_vir = (vir_bytes) proc_addr(nr); break; } + case GET_WHOAMI: { + int len; + /* GET_WHOAMI uses m3 and only uses the message contents for info. */ + m_ptr->GIWHO_EP = who_e; + len = MIN(sizeof(m_ptr->GIWHO_NAME), sizeof(caller->p_name))-1; + strncpy(m_ptr->GIWHO_NAME, caller->p_name, len); + m_ptr->GIWHO_NAME[len] = '\0'; + return OK; + } case GET_MONPARAMS: { - src_phys = kinfo.params_base; /* already is a physical */ - length = kinfo.params_size; + src_vir = (vir_bytes) params_buffer; + length = sizeof(params_buffer); break; } case GET_RANDOMNESS: { @@ -109,44 +120,25 @@ register message *m_ptr; /* pointer to request message */ krandom.bin[i].r_next = 0; } length = sizeof(struct randomness); - src_phys = vir2phys(©); + src_vir = (vir_bytes) © break; } case GET_KMESSAGES: { length = sizeof(struct kmessages); - src_phys = vir2phys(&kmess); + src_vir = (vir_bytes) &kmess; break; } #if DEBUG_TIME_LOCKS case GET_LOCKTIMING: { length = sizeof(timingdata); - src_phys = vir2phys(timingdata); + src_vir = (vir_bytes) timingdata; break; } #endif -#if !( POWERPC ) - case GET_BIOSBUFFER: - bios_buf_vir = (vir_bytes)bios_buf; - bios_buf_len = sizeof(bios_buf); - - length = sizeof(bios_buf_len); - src_phys = vir2phys(&bios_buf_len); - if (length != m_ptr->I_VAL_LEN2_E) return (EINVAL); - if(!isokendpt(m_ptr->m_source, &proc_nr)) - panic("bogus source", m_ptr->m_source); - dst_phys = numap_local(proc_nr, (vir_bytes) m_ptr->I_VAL_PTR2, length); - if (src_phys == 0 || dst_phys == 0) return(EFAULT); - phys_copy(src_phys, dst_phys, length); - - length = sizeof(bios_buf_vir); - src_phys = vir2phys(&bios_buf_vir); - break; -#endif /* #if !( POWERPC ) */ - case GET_IRQACTIDS: { length = sizeof(irq_actids); - src_phys = vir2phys(irq_actids); + src_vir = (vir_bytes) irq_actids; break; } @@ -162,11 +154,10 @@ register message *m_ptr; /* pointer to request message */ /* Try to make the actual copy for the requested data. */ if (m_ptr->I_VAL_LEN > 0 && length > m_ptr->I_VAL_LEN) return (E2BIG); - if(!isokendpt(m_ptr->m_source, &proc_nr)) - panic("bogus source", m_ptr->m_source); - dst_phys = numap_local(proc_nr, (vir_bytes) m_ptr->I_VAL_PTR, length); - if (src_phys == 0 || dst_phys == 0) return(EFAULT); - phys_copy(src_phys, dst_phys, length); + if((ph=umap_local(caller, D, (vir_bytes) m_ptr->I_VAL_PTR,length)) == 0) + return EFAULT; + CHECKRANGE_OR_SUSPEND(caller, ph, length, 1); + data_copy(SYSTEM, src_vir, who_e, (vir_bytes) m_ptr->I_VAL_PTR, length); return(OK); } diff --git a/kernel/system/do_irqctl.c b/kernel/system/do_irqctl.c index 260cc4cde..9625a9825 100644 --- a/kernel/system/do_irqctl.c +++ b/kernel/system/do_irqctl.c @@ -46,8 +46,9 @@ register message *m_ptr; /* pointer to request message */ if (irq_hook_id >= NR_IRQ_HOOKS || irq_hook_id < 0 || irq_hooks[irq_hook_id].proc_nr_e == NONE) return(EINVAL); if (irq_hooks[irq_hook_id].proc_nr_e != m_ptr->m_source) return(EPERM); - if (m_ptr->IRQ_REQUEST == IRQ_ENABLE) + if (m_ptr->IRQ_REQUEST == IRQ_ENABLE) { enable_irq(&irq_hooks[irq_hook_id]); + } else disable_irq(&irq_hooks[irq_hook_id]); break; @@ -64,7 +65,7 @@ register message *m_ptr; /* pointer to request message */ privp= priv(rp); if (!privp) { - kprintf("no priv structure!\n"); + kprintf("do_irqctl: no priv structure!\n"); return EPERM; } if (privp->s_flags & CHECK_IRQ) @@ -143,14 +144,12 @@ irq_hook_t *hook; */ get_randomness(hook->irq); - /* Check if the handler is still alive. If not, forget about the - * interrupt. This should never happen, as processes that die + /* Check if the handler is still alive. + * If it's dead, this should never happen, as processes that die * automatically get their interrupt hooks unhooked. */ - if(!isokendpt(hook->proc_nr_e, &proc)) { - hook->proc_nr_e = NONE; - return 0; - } + if(!isokendpt(hook->proc_nr_e, &proc)) + minix_panic("invalid interrupt handler", hook->proc_nr_e); /* Add a bit for this interrupt to the process' pending interrupts. When * sending the notification message, this bit map will be magically set diff --git a/kernel/system/do_mapdma.c b/kernel/system/do_mapdma.c index 47f0c43ca..449ab0c91 100644 --- a/kernel/system/do_mapdma.c +++ b/kernel/system/do_mapdma.c @@ -31,14 +31,13 @@ register message *m_ptr; /* pointer to request message */ proc = proc_addr(proc_p); - phys_base= umap_local(proc, D, base, size); - if (!phys_base) - { - kprintf("do_mapdma: umap_local failed\n"); + phys_base= umap_virtual(proc, D, base, size); + if (!phys_base) + { + kprintf("do_mapdma: umap_virtual failed\n"); return EFAULT; } m_ptr->CP_DST_ADDR = phys_base; return OK; } - diff --git a/kernel/system/do_newmap.c b/kernel/system/do_newmap.c index a179f5631..028cd290b 100644 --- a/kernel/system/do_newmap.c +++ b/kernel/system/do_newmap.c @@ -16,10 +16,10 @@ PUBLIC int do_newmap(m_ptr) message *m_ptr; /* pointer to request message */ { -/* Handle sys_newmap(). Fetch the memory map from PM. */ +/* Handle sys_newmap(). Fetch the memory map. */ register struct proc *rp; /* process whose map is to be loaded */ - struct mem_map *map_ptr; /* virtual address of map inside caller (PM) */ - phys_bytes src_phys; /* physical address of map at the PM */ + struct mem_map *map_ptr; /* virtual address of map inside caller */ + phys_bytes src_phys; /* physical address of map at the */ int proc; map_ptr = (struct mem_map *) m_ptr->PR_MEM_PTR; @@ -36,18 +36,15 @@ message *m_ptr; /* pointer to request message */ *===========================================================================*/ PUBLIC int newmap(rp, map_ptr) struct proc *rp; /* process whose map is to be loaded */ -struct mem_map *map_ptr; /* virtual address of map inside caller (PM) */ +struct mem_map *map_ptr; /* virtual address of map inside caller */ { -/* Fetch the memory map from PM. */ - phys_bytes src_phys; /* physical address of map at the PM */ - int proc; - - /* Copy the map from PM. */ - src_phys = umap_local(proc_addr(who_p), D, (vir_bytes) map_ptr, - sizeof(rp->p_memmap)); - if (src_phys == 0) return(EFAULT); - phys_copy(src_phys,vir2phys(rp->p_memmap), - (phys_bytes)sizeof(rp->p_memmap)); + int r; +/* Fetch the memory map. */ + if((r=data_copy(who_e, (vir_bytes) map_ptr, + SYSTEM, (vir_bytes) rp->p_memmap, sizeof(rp->p_memmap))) != OK) { + kprintf("newmap: data_copy failed! (%d)\n", r); + return r; + } alloc_segments(rp); diff --git a/kernel/system/do_privctl.c b/kernel/system/do_privctl.c index d1affc6df..c76706dc9 100644 --- a/kernel/system/do_privctl.c +++ b/kernel/system/do_privctl.c @@ -28,8 +28,7 @@ message *m_ptr; /* pointer to request message */ register struct priv *sp; int proc_nr; int priv_id; - int i; - phys_bytes caller_phys, kernel_phys; + int i, r; struct io_range io_range; struct mem_range mem_range; struct priv priv; @@ -100,12 +99,9 @@ message *m_ptr; /* pointer to request message */ if (m_ptr->CTL_ARG_PTR) { /* Copy privilege structure from caller */ - caller_phys = umap_local(caller_ptr, D, - (vir_bytes) m_ptr->CTL_ARG_PTR, sizeof(priv)); - if (caller_phys == 0) - return EFAULT; - kernel_phys = vir2phys(&priv); - phys_copy(caller_phys, kernel_phys, sizeof(priv)); + if((r=data_copy(who_e, (vir_bytes) m_ptr->CTL_ARG_PTR, + SYSTEM, (vir_bytes) &priv, sizeof(priv))) != OK) + return r; /* Copy the call mask */ for (i= 0; iCTL_ARG_PTR, - sizeof(io_range)); - if (caller_phys == 0) - return EFAULT; - kernel_phys = vir2phys(&io_range); - phys_copy(caller_phys, kernel_phys, sizeof(io_range)); + data_copy(who_e, (vir_bytes) m_ptr->CTL_ARG_PTR, + SYSTEM, (vir_bytes) &io_range, sizeof(io_range)); priv(rp)->s_flags |= CHECK_IO_PORT; /* Check I/O accesses */ i= priv(rp)->s_nr_io_range; if (i >= NR_IO_RANGE) @@ -206,12 +198,9 @@ message *m_ptr; /* pointer to request message */ return EPERM; /* Get the memory range */ - caller_phys = umap_local(caller_ptr, D, (vir_bytes) m_ptr->CTL_ARG_PTR, - sizeof(mem_range)); - if (caller_phys == 0) - return EFAULT; - kernel_phys = vir2phys(&mem_range); - phys_copy(caller_phys, kernel_phys, sizeof(mem_range)); + if((r=data_copy(who_e, (vir_bytes) m_ptr->CTL_ARG_PTR, + SYSTEM, (vir_bytes) &mem_range, sizeof(mem_range))) != OK) + return r; priv(rp)->s_flags |= CHECK_MEM; /* Check I/O accesses */ i= priv(rp)->s_nr_mem_range; if (i >= NR_MEM_RANGE) diff --git a/kernel/system/do_profbuf.c b/kernel/system/do_profbuf.c index 7638e046d..334c8ff21 100644 --- a/kernel/system/do_profbuf.c +++ b/kernel/system/do_profbuf.c @@ -25,26 +25,24 @@ register message *m_ptr; /* pointer to request message */ * about the location of their profiling table and the control structure * which is used to enable the kernel to have the tables cleared. */ - int proc_nr, len; + int proc_nr; vir_bytes vir_dst; struct proc *rp; /* Store process name, control struct, table locations. */ - isokendpt(m_ptr->m_source, &proc_nr); + if(!isokendpt(m_ptr->m_source, &proc_nr)) + return EDEADSRCDST; + + if(cprof_procs_no >= NR_SYS_PROCS) + return ENOSPC; + rp = proc_addr(proc_nr); cprof_proc_info[cprof_procs_no].endpt = who_e; cprof_proc_info[cprof_procs_no].name = rp->p_name; - len = (phys_bytes) sizeof (void *); - - vir_dst = (vir_bytes) m_ptr->PROF_CTL_PTR; - cprof_proc_info[cprof_procs_no].ctl = - numap_local(proc_nr, vir_dst, len); - - vir_dst = (vir_bytes) m_ptr->PROF_MEM_PTR; - cprof_proc_info[cprof_procs_no].buf = - numap_local(proc_nr, vir_dst, len); + cprof_proc_info[cprof_procs_no].ctl_v = (vir_bytes) m_ptr->PROF_CTL_PTR; + cprof_proc_info[cprof_procs_no].buf_v = (vir_bytes) m_ptr->PROF_MEM_PTR; cprof_procs_no++; diff --git a/kernel/system/do_safecopy.c b/kernel/system/do_safecopy.c index 5178c3fc8..55744b714 100644 --- a/kernel/system/do_safecopy.c +++ b/kernel/system/do_safecopy.c @@ -14,14 +14,19 @@ * VSCP_VEC_SIZE number of significant elements in vector */ -#include "../system.h" #include #include +#include "../system.h" +#include "../vm.h" + #define MEM_TOP 0xFFFFFFFFUL FORWARD _PROTOTYPE(int safecopy, (endpoint_t, endpoint_t, cp_grant_id_t, int, int, size_t, vir_bytes, vir_bytes, int)); +#define HASGRANTTABLE(gr) \ + (!RTS_ISSET(gr, NO_PRIV) && priv(gr) && priv(gr)->s_grant_table > 0) + /*===========================================================================* * verify_grant * *===========================================================================*/ @@ -38,7 +43,7 @@ endpoint_t *e_granter; /* new granter (magic grants) */ static cp_grant_t g; static int proc_nr; static struct proc *granter_proc; - static phys_bytes phys_grant; + int r; /* Get granter process slot (if valid), and check range of * grant id. @@ -51,23 +56,9 @@ endpoint_t *e_granter; /* new granter (magic grants) */ /* If there is no priv. structure, or no grant table in the * priv. structure, or the grant table in the priv. structure - * is too small for the grant, - * - * then there exists no such grant, so - * - * return EPERM. - * - * (Don't leak how big the grant table is by returning - * EINVAL for grant-out-of-range, in case this turns out to be - * interesting information.) + * is too small for the grant, return EPERM. */ - if(RTS_ISSET(granter_proc, NO_PRIV) || !(priv(granter_proc)) || - priv(granter_proc)->s_grant_table < 1) { - kprintf("verify_grant: grant verify failed in ep %d proc %d: " - "no priv table, or no grant table\n", - granter, proc_nr); - return(EPERM); - } + if(!HASGRANTTABLE(granter_proc)) return EPERM; if(priv(granter_proc)->s_grant_entries <= grant) { static int curr= 0, limit= 100, extra= 20; @@ -94,25 +85,25 @@ endpoint_t *e_granter; /* new granter (magic grants) */ * (presumably) set an invalid grant table entry by returning * EPERM, just like with an invalid grant id. */ - if(!(phys_grant = umap_local(granter_proc, D, - priv(granter_proc)->s_grant_table + sizeof(g)*grant, sizeof(g)))) { - kprintf("verify_grant: grant verify failed: umap failed\n"); + if((r=data_copy(granter, + priv(granter_proc)->s_grant_table + sizeof(g)*grant, + SYSTEM, (vir_bytes) &g, sizeof(g))) != OK) { + kprintf("verify_grant: grant verify: data_copy failed\n"); return EPERM; } - phys_copy(phys_grant, vir2phys(&g), sizeof(g)); - /* Check validity. */ if((g.cp_flags & (CPF_USED | CPF_VALID)) != (CPF_USED | CPF_VALID)) { kprintf( - "verify_grant: grant verify failed: unused or invalid\n"); + "verify_grant: grant failed: invalid (%d flags 0x%lx)\n", + grant, g.cp_flags); return EPERM; } /* Check access of grant. */ if(((g.cp_flags & access) != access)) { kprintf( - "verify_grant: grant verify failed: access invalid; want %x, have %x\n", + "verify_grant: grant verify failed: access invalid; want 0x%x, have 0x%x\n", access, g.cp_flags); return EPERM; } @@ -210,6 +201,11 @@ int access; /* CPF_READ for a copy from granter to grantee, CPF_WRITE static vir_bytes v_offset; int r; endpoint_t new_granter, *src, *dst; + struct proc *granter_p; + + /* See if there is a reasonable grant table. */ + if(!(granter_p = endpoint_lookup(granter))) return EINVAL; + if(!HASGRANTTABLE(granter_p)) return EPERM; /* Decide who is src and who is dst. */ if(access & CPF_READ) { @@ -227,9 +223,11 @@ int access; /* CPF_READ for a copy from granter to grantee, CPF_WRITE if (curr < limit+extra) { +#if 0 kprintf( "grant %d verify to copy %d->%d by %d failed: err %d\n", grantid, *src, *dst, grantee, r); +#endif } else if (curr == limit+extra) { kprintf( @@ -265,7 +263,7 @@ int access; /* CPF_READ for a copy from granter to grantee, CPF_WRITE } /* Do the regular copy. */ - return virtual_copy(&v_src, &v_dst, bytes); + return virtual_copy_vmcheck(&v_src, &v_dst, bytes); } @@ -288,7 +286,7 @@ register message *m_ptr; /* pointer to request message */ src_seg = SCP_INFO2SEG(m_ptr->SCP_INFO); dst_seg = D; access = CPF_WRITE; - } else panic("Impossible system call nr. ", sys_call_code); + } else minix_panic("Impossible system call nr. ", sys_call_code); return safecopy(m_ptr->SCP_FROM_TO, who_e, m_ptr->SCP_GID, src_seg, dst_seg, m_ptr->SCP_BYTES, m_ptr->SCP_OFFSET, @@ -304,6 +302,7 @@ register message *m_ptr; /* pointer to request message */ static struct vscp_vec vec[SCPVEC_NR]; static struct vir_addr src, dst; int r, i, els; + size_t bytes; /* Set vector copy parameters. */ src.proc_nr_e = who_e; @@ -314,9 +313,10 @@ register message *m_ptr; /* pointer to request message */ /* No. of vector elements. */ els = m_ptr->VSCP_VEC_SIZE; + bytes = els * sizeof(struct vscp_vec); /* Obtain vector of copies. */ - if((r=virtual_copy(&src, &dst, els * sizeof(struct vscp_vec))) != OK) + if((r=virtual_copy_vmcheck(&src, &dst, bytes)) != OK) return r; /* Perform safecopies. */ diff --git a/kernel/system/do_sigreturn.c b/kernel/system/do_sigreturn.c index 894260d44..aedf2a603 100644 --- a/kernel/system/do_sigreturn.c +++ b/kernel/system/do_sigreturn.c @@ -26,18 +26,16 @@ message *m_ptr; /* pointer to request message */ */ struct sigcontext sc; register struct proc *rp; - phys_bytes src_phys; - int proc; + int proc, r; if (! isokendpt(m_ptr->SIG_ENDPT, &proc)) return(EINVAL); if (iskerneln(proc)) return(EPERM); rp = proc_addr(proc); /* Copy in the sigcontext structure. */ - src_phys = umap_local(rp, D, (vir_bytes) m_ptr->SIG_CTXT_PTR, - (vir_bytes) sizeof(struct sigcontext)); - if (src_phys == 0) return(EFAULT); - phys_copy(src_phys, vir2phys(&sc), (phys_bytes) sizeof(struct sigcontext)); + if((r=data_copy(m_ptr->SIG_ENDPT, (vir_bytes) m_ptr->SIG_CTXT_PTR, + SYSTEM, (vir_bytes) &sc, sizeof(struct sigcontext))) != OK) + return r; /* Restore user bits of psw from sc, maintain system bits from proc. */ sc.sc_psw = (sc.sc_psw & X86_FLAGS_USER) | diff --git a/kernel/system/do_sigsend.c b/kernel/system/do_sigsend.c index 0b37bac89..fc1980063 100644 --- a/kernel/system/do_sigsend.c +++ b/kernel/system/do_sigsend.c @@ -25,20 +25,18 @@ message *m_ptr; /* pointer to request message */ struct sigmsg smsg; register struct proc *rp; - phys_bytes src_phys, dst_phys; struct sigcontext sc, *scp; struct sigframe fr, *frp; - int proc; + int proc, r; if (!isokendpt(m_ptr->SIG_ENDPT, &proc)) return(EINVAL); if (iskerneln(proc)) return(EPERM); rp = proc_addr(proc); /* Get the sigmsg structure into our address space. */ - src_phys = umap_local(proc_addr(PM_PROC_NR), D, (vir_bytes) - m_ptr->SIG_CTXT_PTR, (vir_bytes) sizeof(struct sigmsg)); - if (src_phys == 0) return(EFAULT); - phys_copy(src_phys,vir2phys(&smsg),(phys_bytes) sizeof(struct sigmsg)); + if((r=data_copy(PM_PROC_NR, (vir_bytes) m_ptr->SIG_CTXT_PTR, + SYSTEM, (vir_bytes) &smsg, (phys_bytes) sizeof(struct sigmsg))) != OK) + return r; /* Compute the user stack pointer where sigcontext will be stored. */ scp = (struct sigcontext *) smsg.sm_stkptr - 1; @@ -56,10 +54,9 @@ message *m_ptr; /* pointer to request message */ sc.sc_mask = smsg.sm_mask; /* Copy the sigcontext structure to the user's stack. */ - dst_phys = umap_local(rp, D, (vir_bytes) scp, - (vir_bytes) sizeof(struct sigcontext)); - if (dst_phys == 0) return(EFAULT); - phys_copy(vir2phys(&sc), dst_phys, (phys_bytes) sizeof(struct sigcontext)); + if((r=data_copy(SYSTEM, (vir_bytes) &sc, m_ptr->SIG_ENDPT, (vir_bytes) scp, + (vir_bytes) sizeof(struct sigcontext))) != OK) + return r; /* Initialize the sigframe structure. */ frp = (struct sigframe *) scp - 1; @@ -73,10 +70,10 @@ message *m_ptr; /* pointer to request message */ fr.sf_retadr = (void (*)()) smsg.sm_sigreturn; /* Copy the sigframe structure to the user's stack. */ - dst_phys = umap_local(rp, D, (vir_bytes) frp, - (vir_bytes) sizeof(struct sigframe)); - if (dst_phys == 0) return(EFAULT); - phys_copy(vir2phys(&fr), dst_phys, (phys_bytes) sizeof(struct sigframe)); + if((r=data_copy(SYSTEM, (vir_bytes) &fr, m_ptr->SIG_ENDPT, (vir_bytes) frp, + (vir_bytes) sizeof(struct sigframe))) != OK) + return r; + #if ( _MINIX_CHIP == _CHIP_POWERPC ) /* stuff that can't be done in the assembler code. */ /* When the signal handlers C code is called it will write this value @@ -95,8 +92,13 @@ message *m_ptr; /* pointer to request message */ /* Reschedule if necessary. */ if(RTS_ISSET(rp, NO_PRIORITY)) RTS_LOCK_UNSET(rp, NO_PRIORITY); - else + else { + struct proc *caller; + caller = proc_addr(who_p); kprintf("system: warning: sigsend a running process\n"); + kprintf("caller stack: "); + proc_stacktrace(caller); + } return(OK); } diff --git a/kernel/system/do_sprofile.c b/kernel/system/do_sprofile.c index 6c6198735..323caa498 100644 --- a/kernel/system/do_sprofile.c +++ b/kernel/system/do_sprofile.c @@ -17,6 +17,9 @@ #if SPROFILE +/* user address to write info struct */ +PRIVATE vir_bytes sprof_info_addr_vir; + /*===========================================================================* * do_sprofile * *===========================================================================*/ @@ -41,15 +44,14 @@ register message *m_ptr; /* pointer to request message */ return EBUSY; } - isokendpt(m_ptr->PROF_ENDPT, &proc_nr); + /* Test endpoint number. */ + if(!isokendpt(m_ptr->PROF_ENDPT, &proc_nr)) + return EINVAL; - vir_dst = (vir_bytes) m_ptr->PROF_CTL_PTR; - length = (phys_bytes) sizeof (int *); - sprof_info_addr = numap_local(proc_nr, vir_dst, length); - - vir_dst = (vir_bytes) m_ptr->PROF_MEM_PTR; - length = (phys_bytes) sizeof (char *); - sprof_data_addr = numap_local(proc_nr, vir_dst, length); + /* Set parameters for statistical profiler. */ + sprof_ep = m_ptr->PROF_ENDPT; + sprof_info_addr_vir = (vir_bytes) m_ptr->PROF_CTL_PTR; + sprof_data_addr_vir = (vir_bytes) m_ptr->PROF_MEM_PTR; sprof_info.mem_used = 0; sprof_info.total_samples = 0; @@ -80,8 +82,8 @@ register message *m_ptr; /* pointer to request message */ stop_profile_clock(); - phys_copy(vir2phys((vir_bytes) &sprof_info), - sprof_info_addr, (phys_bytes) sizeof(sprof_info)); + data_copy(SYSTEM, (vir_bytes) &sprof_info, + sprof_ep, sprof_info_addr_vir, sizeof(sprof_info)); return OK; diff --git a/kernel/system/do_trace.c b/kernel/system/do_trace.c index 0e12f0ba5..988a3b99c 100644 --- a/kernel/system/do_trace.c +++ b/kernel/system/do_trace.c @@ -40,7 +40,6 @@ register message *m_ptr; */ register struct proc *rp; - phys_bytes src, dst; vir_bytes tr_addr = (vir_bytes) m_ptr->CTL_ADDRESS; long tr_data = m_ptr->CTL_DATA; int tr_request = m_ptr->CTL_REQUEST; @@ -48,6 +47,26 @@ register message *m_ptr; unsigned char ub; int i; +#define COPYTOPROC(seg, addr, myaddr, length) { \ + struct vir_addr fromaddr, toaddr; \ + fromaddr.proc_nr_e = SYSTEM; \ + toaddr.proc_nr_e = tr_proc_nr_e; \ + fromaddr.offset = (myaddr); \ + toaddr.offset = (addr); \ + fromaddr.segment = D; \ + toaddr.segment = (seg); \ +} + +#define COPYFROMPROC(seg, addr, myaddr, length) { \ + struct vir_addr fromaddr, toaddr; \ + fromaddr.proc_nr_e = tr_proc_nr_e; \ + toaddr.proc_nr_e = SYSTEM; \ + fromaddr.offset = (addr); \ + toaddr.offset = (myaddr); \ + fromaddr.segment = (seg); \ + toaddr.segment = D; \ +} + if(!isokendpt(tr_proc_nr_e, &tr_proc_nr)) return(EINVAL); if (iskerneln(tr_proc_nr)) return(EPERM); @@ -61,16 +80,14 @@ register message *m_ptr; case T_GETINS: /* return value from instruction space */ if (rp->p_memmap[T].mem_len != 0) { - if ((src = umap_local(rp, T, tr_addr, TR_VLSIZE)) == 0) return(EIO); - phys_copy(src, vir2phys(&tr_data), (phys_bytes) sizeof(long)); + COPYTOPROC(T, tr_addr, (vir_bytes) &tr_data, sizeof(long)); m_ptr->CTL_DATA = tr_data; break; } /* Text space is actually data space - fall through. */ case T_GETDATA: /* return value from data space */ - if ((src = umap_local(rp, D, tr_addr, TR_VLSIZE)) == 0) return(EIO); - phys_copy(src, vir2phys(&tr_data), (phys_bytes) sizeof(long)); + COPYTOPROC(D, tr_addr, (vir_bytes) &tr_data, sizeof(long)); m_ptr->CTL_DATA= tr_data; break; @@ -83,16 +100,14 @@ register message *m_ptr; case T_SETINS: /* set value in instruction space */ if (rp->p_memmap[T].mem_len != 0) { - if ((dst = umap_local(rp, T, tr_addr, TR_VLSIZE)) == 0) return(EIO); - phys_copy(vir2phys(&tr_data), dst, (phys_bytes) sizeof(long)); + COPYFROMPROC(T, tr_addr, (vir_bytes) &tr_data, sizeof(long)); m_ptr->CTL_DATA = 0; break; } /* Text space is actually data space - fall through. */ case T_SETDATA: /* set value in data space */ - if ((dst = umap_local(rp, D, tr_addr, TR_VLSIZE)) == 0) return(EIO); - phys_copy(vir2phys(&tr_data), dst, (phys_bytes) sizeof(long)); + COPYFROMPROC(D, tr_addr, (vir_bytes) &tr_data, sizeof(long)); m_ptr->CTL_DATA = 0; break; @@ -136,28 +151,12 @@ register message *m_ptr; break; case T_READB_INS: /* get value from instruction space */ - if (rp->p_memmap[T].mem_len != 0) { - if ((dst = umap_local(rp, T, tr_addr, 1)) == 0) return(EFAULT); - phys_copy(dst, vir2phys(&ub), (phys_bytes) 1); - m_ptr->CTL_DATA = ub; - break; - } - - if ((dst = umap_local(rp, D, tr_addr, 1)) == 0) return(EFAULT); - phys_copy(dst, vir2phys(&ub), (phys_bytes) 1); + COPYFROMPROC(rp->p_memmap[T].mem_len > 0 ? T : D, tr_addr, (vir_bytes) &ub, 1); m_ptr->CTL_DATA = ub; break; case T_WRITEB_INS: /* set value in instruction space */ - if (rp->p_memmap[T].mem_len != 0) { - if ((dst = umap_local(rp, T, tr_addr, 1)) == 0) return(EFAULT); - phys_copy(vir2phys(&tr_data), dst, (phys_bytes) 1); - m_ptr->CTL_DATA = 0; - break; - } - - if ((dst = umap_local(rp, D, tr_addr, 1)) == 0) return(EFAULT); - phys_copy(vir2phys(&tr_data), dst, (phys_bytes) 1); + COPYTOPROC(rp->p_memmap[T].mem_len > 0 ? T : D,tr_addr, (vir_bytes) &tr_data, 1); m_ptr->CTL_DATA = 0; break; diff --git a/kernel/system/do_umap.c b/kernel/system/do_umap.c index 933609523..7c235ba46 100644 --- a/kernel/system/do_umap.c +++ b/kernel/system/do_umap.c @@ -10,6 +10,7 @@ */ #include "../system.h" +#include "../vm.h" #if USE_UMAP @@ -25,8 +26,11 @@ register message *m_ptr; /* pointer to request message */ vir_bytes offset = m_ptr->CP_SRC_ADDR; int count = m_ptr->CP_NR_BYTES; int endpt = (int) m_ptr->CP_SRC_ENDPT; - int proc_nr; - phys_bytes phys_addr; + int proc_nr, r; + int naughty = 0; + phys_bytes phys_addr = 0, lin_addr = 0; + int caller_pn; + struct proc *targetpr, *caller; /* Verify process number. */ if (endpt == SELF) @@ -34,27 +38,88 @@ register message *m_ptr; /* pointer to request message */ else if (! isokendpt(endpt, &proc_nr)) return(EINVAL); + targetpr = proc_addr(proc_nr); + + okendpt(who_e, &caller_pn); + caller = proc_addr(caller_pn); /* See which mapping should be made. */ switch(seg_type) { case LOCAL_SEG: - phys_addr = umap_local(proc_addr(proc_nr), seg_index, offset, count); + phys_addr = lin_addr = umap_local(targetpr, seg_index, offset, count); + if(!lin_addr) return EFAULT; + CHECKRANGE_OR_SUSPEND(targetpr, lin_addr, count, 1); + naughty = 1; break; case REMOTE_SEG: - phys_addr = umap_remote(proc_addr(proc_nr), seg_index, offset, count); + phys_addr = lin_addr = umap_remote(targetpr, seg_index, offset, count); + if(!lin_addr) return EFAULT; + CHECKRANGE_OR_SUSPEND(targetpr, lin_addr, count, 1); + naughty = 1; break; -#if _MINIX_CHIP == _CHIP_INTEL - case BIOS_SEG: - phys_addr = umap_bios(proc_addr(proc_nr), offset, count); - break; -#endif case GRANT_SEG: - phys_addr = umap_grant(proc_addr(proc_nr), offset, count); + naughty = 1; + case LOCAL_VM_SEG: + if(seg_index == MEM_GRANT || seg_type == GRANT_SEG) { + vir_bytes newoffset; + endpoint_t newep; + int new_proc_nr; + + if(verify_grant(targetpr->p_endpoint, ANY, offset, count, 0, 0, + &newoffset, &newep) != OK) { + kprintf("SYSTEM: do_umap: verify_grant in %s, grant %d, bytes 0x%lx, failed, caller %s\n", targetpr->p_name, offset, count, caller->p_name); + proc_stacktrace(caller); + return EFAULT; + } + + if(!isokendpt(newep, &new_proc_nr)) { + kprintf("SYSTEM: do_umap: isokendpt failed\n"); + return EFAULT; + } + + /* New lookup. */ + offset = newoffset; + targetpr = proc_addr(new_proc_nr); + seg_index = D; + } + + if(seg_index == T || seg_index == D || seg_index == S) { + phys_addr = lin_addr = umap_local(targetpr, seg_index, offset, count); + } else { + kprintf("SYSTEM: bogus seg type 0x%lx\n", seg_index); + return EFAULT; + } + if(!lin_addr) { + kprintf("SYSTEM:do_umap: umap_local failed\n"); + return EFAULT; + } + CHECKRANGE_OR_SUSPEND(targetpr, lin_addr, count, 1); + if(vm_lookup(targetpr, lin_addr, &phys_addr, NULL) != OK) { + kprintf("SYSTEM:do_umap: vm_lookup failed\n"); + return EFAULT; + } + if(phys_addr == 0) + minix_panic("vm_lookup returned zero physical address", NO_NUM); break; default: - return(EINVAL); + if((r=arch_umap(targetpr, offset, count, seg_type, &lin_addr)) + != OK) + return r; + phys_addr = lin_addr; } + + if(vm_running && !vm_contiguous(targetpr, lin_addr, count)) { + kprintf("SYSTEM:do_umap: not contiguous\n"); + return EFAULT; + } + m_ptr->CP_DST_ADDR = phys_addr; + if(naughty || phys_addr == 0) { + kprintf("kernel: umap 0x%x done by %d / %s, pc 0x%lx, 0x%lx -> 0x%lx\n", + seg_type, who_e, caller->p_name, caller->p_reg.pc, offset, phys_addr); + kprintf("caller stack: "); + proc_stacktrace(caller); + } return (phys_addr == 0) ? EFAULT: OK; } diff --git a/kernel/system/do_unused.c b/kernel/system/do_unused.c index 4e2b0001b..2a9163308 100644 --- a/kernel/system/do_unused.c +++ b/kernel/system/do_unused.c @@ -10,7 +10,7 @@ PUBLIC int do_unused(m) message *m; /* pointer to request message */ { - kprintf("SYSTEM: got unused request %d from %d", m->m_type, m->m_source); + kprintf("SYSTEM: got unused request %d from %d\n", m->m_type, m->m_source); return(EBADREQUEST); /* illegal message type */ } diff --git a/kernel/system/do_vcopy.c b/kernel/system/do_vcopy.c index efdc7f65c..b43d50f6f 100644 --- a/kernel/system/do_vcopy.c +++ b/kernel/system/do_vcopy.c @@ -25,13 +25,13 @@ register message *m_ptr; /* pointer to request message */ * requests. Although a single handler function is used, there are two * different kernel calls so that permissions can be checked. */ - int nr_req; + int nr_req, r; vir_bytes caller_vir; - phys_bytes caller_phys; - phys_bytes kernel_phys; phys_bytes bytes; int i,s; struct vir_cp_req *req; + struct vir_addr src, dst; + struct proc *pr; { static int first=1; if (first) @@ -41,17 +41,23 @@ register message *m_ptr; /* pointer to request message */ } } + if(!(pr = endpoint_lookup(who_e))) + minix_panic("do_vcopy: caller doesn't exist", who_e); + /* Check if request vector size is ok. */ nr_req = (unsigned) m_ptr->VCP_VEC_SIZE; if (nr_req > VCOPY_VEC_SIZE) return(EINVAL); bytes = nr_req * sizeof(struct vir_cp_req); /* Calculate physical addresses and copy (port,value)-pairs from user. */ - caller_vir = (vir_bytes) m_ptr->VCP_VEC_ADDR; - caller_phys = umap_local(proc_addr(who_p), D, caller_vir, bytes); - if (0 == caller_phys) return(EFAULT); - kernel_phys = vir2phys(vir_cp_req); - phys_copy(caller_phys, kernel_phys, (phys_bytes) bytes); + src.segment = dst.segment = D; + src.proc_nr_e = who_e; + dst.proc_nr_e = SYSTEM; + dst.offset = (vir_bytes) vir_cp_req; + src.offset = (vir_bytes) m_ptr->VCP_VEC_ADDR; + + if((r=virtual_copy_vmcheck(&src, &dst, bytes)) != OK) + return r; /* Assume vector with requests is correct. Try to copy everything. */ m_ptr->VCP_NR_OK = 0; @@ -62,7 +68,7 @@ register message *m_ptr; /* pointer to request message */ /* Check if physical addressing is used without SYS_PHYSVCOPY. */ if (((req->src.segment | req->dst.segment) & PHYS_SEG) && m_ptr->m_type != SYS_PHYSVCOPY) return(EPERM); - if ((s=virtual_copy(&req->src, &req->dst, req->count)) != OK) + if ((s=virtual_copy_vmcheck(&req->src, &req->dst, req->count)) != OK) return(s); m_ptr->VCP_NR_OK ++; } diff --git a/kernel/system/do_vdevio.c b/kernel/system/do_vdevio.c index 268d25baa..9fe1a3c64 100644 --- a/kernel/system/do_vdevio.c +++ b/kernel/system/do_vdevio.c @@ -36,14 +36,13 @@ register message *m_ptr; /* pointer to request message */ int vec_size; /* size of vector */ int io_in; /* true if input */ size_t bytes; /* # bytes to be copied */ - vir_bytes caller_vir; /* virtual address at caller */ - phys_bytes caller_phys; /* physical address at caller */ port_t port; int i, j, io_size, nr_io_range; int io_dir, io_type; struct proc *rp; struct priv *privp; struct io_range *iorp; + int r; /* Get the request, size of the request vector, and check the values. */ io_dir = m_ptr->DIO_REQUEST & _DIO_DIRMASK; @@ -69,11 +68,10 @@ register message *m_ptr; /* pointer to request message */ } if (bytes > sizeof(vdevio_buf)) return(E2BIG); - /* Calculate physical addresses and copy (port,value)-pairs from user. */ - caller_vir = (vir_bytes) m_ptr->DIO_VEC_ADDR; - caller_phys = umap_local(proc_addr(who_p), D, caller_vir, bytes); - if (0 == caller_phys) return(EFAULT); - phys_copy(caller_phys, vir2phys(vdevio_buf), (phys_bytes) bytes); + /* Copy (port,value)-pairs from user. */ + if((r=data_copy(who_e, (vir_bytes) m_ptr->DIO_VEC_ADDR, + SYSTEM, (vir_bytes) vdevio_buf, bytes)) != OK) + return r; rp= proc_addr(who_p); privp= priv(rp); @@ -110,7 +108,20 @@ register message *m_ptr; /* pointer to request message */ * the entire switch is wrapped in lock() and unlock() to prevent the I/O * batch from being interrupted. */ - lock(13, "do_vdevio"); +#if 0 + if(who_e == 71091) { + static int vd = 0; + if(vd++ < 100) { + kprintf("proc %d does vdevio no %d; type %d, direction %s\n", + who_e, vd, io_type, io_in ? "input" : "output"); + kprintf("("); + for (i=0; iDIO_VEC_ADDR, + (phys_bytes) bytes)) != OK) + return r; return(OK); bad: - panic("do_vdevio: unaligned port\n", port); + minix_panic("do_vdevio: unaligned port", port); return EPERM; } diff --git a/kernel/system/do_vm.c b/kernel/system/do_vm.c deleted file mode 100644 index 0dc837a62..000000000 --- a/kernel/system/do_vm.c +++ /dev/null @@ -1,83 +0,0 @@ -/* The system call implemented in this file: - * m_type: SYS_VM_MAP - * - * The parameters for this system call are: - * m4_l1: Process that requests map (VM_MAP_ENDPT) - * m4_l2: Map (TRUE) or unmap (FALSE) (VM_MAP_MAPUNMAP) - * m4_l3: Base address (VM_MAP_BASE) - * m4_l4: Size (VM_MAP_SIZE) - * m4_l5: address (VM_MAP_ADDR) - */ -#include "../system.h" - -PRIVATE int vm_needs_init= 1; - -#include - -/*===========================================================================* - * do_vm_map * - *===========================================================================*/ -PUBLIC int do_vm_map(m_ptr) -message *m_ptr; /* pointer to request message */ -{ - int proc_nr, do_map; - phys_bytes base, size, offset, p_phys; - struct proc *pp; - - /* do_serial_debug= 1; */ - if (vm_needs_init) - { - vm_needs_init= 0; - vm_init(); - } - - if (m_ptr->VM_MAP_ENDPT == SELF) { - proc_nr = who_p; - } else { - if(!isokendpt(m_ptr->VM_MAP_ENDPT, &proc_nr)) - return EINVAL; - } - - do_map= m_ptr->VM_MAP_MAPUNMAP; - base= m_ptr->VM_MAP_BASE; - size= m_ptr->VM_MAP_SIZE; - offset= m_ptr->VM_MAP_ADDR; - - pp= proc_addr(proc_nr); - p_phys= umap_local(pp, D, base, size); - if (p_phys == 0) - return EFAULT; - - if (do_map) - { - pp->p_misc_flags |= MF_VM; - - vm_map_range(p_phys, size, offset); - } - else - { - vm_map_range(p_phys, size, p_phys); - } - - return OK; -} - - -/*===========================================================================* - * vm_map_default * - *===========================================================================*/ -PUBLIC void vm_map_default(pp) -struct proc *pp; -{ - phys_bytes base_clicks, size_clicks; - - if (vm_needs_init) - panic("vm_map_default: VM not initialized?", NO_NUM); - pp->p_misc_flags &= ~MF_VM; - base_clicks= pp->p_memmap[D].mem_phys; - size_clicks= pp->p_memmap[S].mem_phys+pp->p_memmap[S].mem_len - - base_clicks; - vm_map_range(base_clicks << CLICK_SHIFT, - size_clicks << CLICK_SHIFT, base_clicks << CLICK_SHIFT); -} - diff --git a/kernel/system/do_vmctl.c b/kernel/system/do_vmctl.c new file mode 100644 index 000000000..8517c57d7 --- /dev/null +++ b/kernel/system/do_vmctl.c @@ -0,0 +1,104 @@ +/* The kernel call implemented in this file: + * m_type: SYS_VMCTL + * + * The parameters for this kernel call are: + * SVMCTL_WHO which process + * SVMCTL_PARAM set this setting (VMCTL_*) + * SVMCTL_VALUE to this value + */ + +#include "../system.h" +#include "../vm.h" +#include "../debug.h" +#include + +/*===========================================================================* + * do_vmctl * + *===========================================================================*/ +PUBLIC int do_vmctl(m_ptr) +register message *m_ptr; /* pointer to request message */ +{ + int proc_nr, i; + endpoint_t ep = m_ptr->SVMCTL_WHO; + struct proc *p, *rp; + + if(ep == SELF) { ep = m_ptr->m_source; } + + vm_init(); + + if(m_ptr->m_source != VM_PROC_NR) { + kprintf("do_vmctl: source %d, not VM\n", m_ptr->m_source); + return ENOSYS; + } + + if(!isokendpt(ep, &proc_nr)) { + kprintf("do_vmctl: unexpected endpoint %d from VM\n", ep); + return EINVAL; + } + + p = proc_addr(proc_nr); + + switch(m_ptr->SVMCTL_PARAM) { + case VMCTL_CLEAR_PAGEFAULT: + RTS_LOCK_UNSET(p, PAGEFAULT); + return OK; + case VMCTL_MEMREQ_GET: + /* Send VM the information about the memory request. */ + if(!(rp = vmrequest)) + return ESRCH; + if(!RTS_ISSET(rp, VMREQUEST)) + minix_panic("do_vmctl: no VMREQUEST set", NO_NUM); + + /* Reply with request fields. */ + m_ptr->SVMCTL_MRG_ADDR = (char *) rp->p_vmrequest.start; + m_ptr->SVMCTL_MRG_LEN = rp->p_vmrequest.length; + m_ptr->SVMCTL_MRG_WRITE = rp->p_vmrequest.writeflag; + m_ptr->SVMCTL_MRG_EP = rp->p_vmrequest.who; + rp->p_vmrequest.vmresult = VMSUSPEND; + + /* Remove from request chain. */ + vmrequest = vmrequest->p_vmrequest.nextrequestor; + + return OK; + case VMCTL_MEMREQ_REPLY: + if(!(rp = p->p_vmrequest.requestor)) + minix_panic("do_vmctl: no requestor set", ep); + p->p_vmrequest.requestor = NULL; + if(!RTS_ISSET(rp, VMREQUEST)) + minix_panic("do_vmctl: no VMREQUEST set", ep); + if(rp->p_vmrequest.vmresult != VMSUSPEND) + minix_panic("do_vmctl: result not VMSUSPEND set", + rp->p_vmrequest.vmresult); + rp->p_vmrequest.vmresult = m_ptr->SVMCTL_VALUE; + if(rp->p_vmrequest.vmresult == VMSUSPEND) + minix_panic("VM returned VMSUSPEND?", NO_NUM); + if(rp->p_vmrequest.vmresult != OK) + kprintf("SYSTEM: VM replied %d to mem request\n", + rp->p_vmrequest.vmresult); + + /* Put on restart chain. */ + rp->p_vmrequest.nextrestart = vmrestart; + vmrestart = rp; + +#if DEBUG_VMASSERT + /* Sanity check. */ + if(rp->p_vmrequest.vmresult == OK) { + if(CHECKRANGE(p, + rp->p_vmrequest.start, + rp->p_vmrequest.length, + rp->p_vmrequest.writeflag) != OK) { +kprintf("SYSTEM: request %d:0x%lx-0x%lx, wrflag %d, failed\n", + rp->p_endpoint, + rp->p_vmrequest.start, rp->p_vmrequest.start + rp->p_vmrequest.length, + rp->p_vmrequest.writeflag); + + minix_panic("SYSTEM: fail but VM said OK", NO_NUM); + } + } +#endif + return OK; + } + + /* Try architecture-specific vmctls. */ + return arch_do_vmctl(m_ptr, p); +} diff --git a/kernel/table.c b/kernel/table.c index dd2e5c2ed..594370af5 100755 --- a/kernel/table.c +++ b/kernel/table.c @@ -68,7 +68,8 @@ PUBLIC char *t_stack[TOT_STACK_SPACE / sizeof(char *)]; #define NUL_M 0 #define SRV_M (~0) #define SYS_M (~0) -#define USR_M (s(PM_PROC_NR) | s(FS_PROC_NR) | s(RS_PROC_NR) | s(SYSTEM)) +#define USR_M (s(PM_PROC_NR) | s(FS_PROC_NR) | s(RS_PROC_NR) | s(SYSTEM) | \ + s(VM_PROC_NR)) #define DRV_M (USR_M | s(SYSTEM) | s(CLOCK) | s(DS_PROC_NR) | s(LOG_PROC_NR) | s(TTY_PROC_NR)) /* Define kernel calls that processes are allowed to make. This is not looking @@ -90,10 +91,11 @@ PRIVATE int pm_c[] = { SYS_ALL_CALLS }, rs_c[] = { SYS_ALL_CALLS }, ds_c[] = { SYS_ALL_CALLS }, + vm_c[] = { SYS_ALL_CALLS }, drv_c[] = { DRV_C }, - tty_c[] = { DRV_C, SYS_PHYSCOPY, SYS_ABORT, SYS_VM_MAP, SYS_IOPENABLE, + tty_c[] = { DRV_C, SYS_PHYSCOPY, SYS_ABORT, SYS_IOPENABLE, SYS_READBIOS }, - mem_c[] = { DRV_C, SYS_PHYSCOPY, SYS_PHYSVCOPY, SYS_VM_MAP, SYS_IOPENABLE }; + mem_c[] = { DRV_C, SYS_PHYSCOPY, SYS_PHYSVCOPY, SYS_IOPENABLE }; /* The system image table lists all programs that are part of the boot image. * The order of the entries here MUST agree with the order of the programs @@ -122,6 +124,7 @@ PUBLIC struct boot_image image[] = { {MEM_PROC_NR, 0,SRV_F, 4, 2, 0, SRV_T, SYS_M,c(mem_c),"memory"}, {LOG_PROC_NR, 0,SRV_F, 4, 2, 0, SRV_T, SYS_M,c(drv_c),"log" }, {MFS_PROC_NR, 0,SRV_F, 32, 4, 0, SRV_T, SRV_M, c(fs_c),"mfs" }, +{VM_PROC_NR, 0,SRV_F, 32, 3, 0, SRV_T, SRV_M, c(vm_c),"vm" }, {INIT_PROC_NR, 0,USR_F, 8, USER_Q, 0, USR_T, USR_M, no_c,"init" }, }; diff --git a/kernel/type.h b/kernel/type.h index 6f3bff9d1..98687b089 100755 --- a/kernel/type.h +++ b/kernel/type.h @@ -27,13 +27,6 @@ struct boot_image { endpoint_t endpoint; /* endpoint number when started */ }; -/* The kernel outputs diagnostic messages in a circular buffer. */ -struct kmessages { - int km_next; /* next index to write */ - int km_size; /* current size in buffer */ - char km_buf[KMESS_BUF_SIZE]; /* buffer for messages */ -}; - struct randomness { struct { int r_next; /* next index to write */ @@ -57,4 +50,14 @@ typedef struct irq_hook { typedef int (*irq_handler_t)(struct irq_hook *); +/* Timing measurements. */ +struct lock_timingdata { + char names[TIMING_NAME]; + unsigned long lock_timings[TIMING_POINTS]; + unsigned long lock_timings_range[2]; + unsigned long binsize, resets, misses, measurements; +}; +EXTERN struct lock_timingdata timingdata[TIMING_CATEGORIES]; + + #endif /* TYPE_H */ diff --git a/kernel/utility.c b/kernel/utility.c index 07c8a2744..b7377b1cc 100755 --- a/kernel/utility.c +++ b/kernel/utility.c @@ -1,5 +1,5 @@ /* This file contains a collection of miscellaneous procedures: - * panic: abort MINIX due to a fatal error + * minix_panic: abort MINIX due to a fatal error * kprintf: (from lib/sysutil/kprintf.c) * kputc: buffered putc used by kernel kprintf */ @@ -9,26 +9,32 @@ #include #include +#include + +#include +#include /*===========================================================================* - * panic * + * minix_panic * *===========================================================================*/ -PUBLIC void panic(mess,nr) -_CONST char *mess; +PUBLIC void minix_panic(mess,nr) +char *mess; int nr; { /* The system has run aground of a fatal kernel error. Terminate execution. */ - static int panicking = 0; - if (panicking ++) return; /* prevent recursive panics */ + if (minix_panicing ++) return; /* prevent recursive panics */ if (mess != NULL) { - kprintf("\nKernel panic: %s", mess); - if (nr != NO_NUM) kprintf(" %d", nr); + kprintf("kernel panic: %s", mess); + if(nr != NO_NUM) + kprintf(" %d", nr); kprintf("\n"); + kprintf("kernel stacktrace: "); + util_stacktrace(); } /* Abort MINIX. */ - prepare_shutdown(RBT_PANIC); + minix_shutdown(NULL); } @@ -36,6 +42,7 @@ int nr; #define printf kprintf #include "../lib/sysutil/kprintf.c" + #define END_OF_KMESS 0 /*===========================================================================* @@ -54,11 +61,12 @@ int c; /* character to append */ ser_putc(c); } kmess.km_buf[kmess.km_next] = c; /* put normal char in buffer */ - if (kmess.km_size < KMESS_BUF_SIZE) + if (kmess.km_size < sizeof(kmess.km_buf)) kmess.km_size += 1; - kmess.km_next = (kmess.km_next + 1) % KMESS_BUF_SIZE; + kmess.km_next = (kmess.km_next + 1) % _KMESS_BUF_SIZE; } else { int p, outprocs[] = OUTPUT_PROCS_ARRAY; + if(minix_panicing) return; for(p = 0; outprocs[p] != NONE; p++) { if(isokprocn(outprocs[p]) && !isemptyn(outprocs[p])) { send_sig(outprocs[p], SIGKMESS); diff --git a/kernel/vm.h b/kernel/vm.h new file mode 100644 index 000000000..9e0b615da --- /dev/null +++ b/kernel/vm.h @@ -0,0 +1,20 @@ + +#ifndef _VM_H +#define _VM_H 1 + +#define CHECKRANGE_OR_SUSPEND(pr, start, length, wr) { int mr; \ + if(vm_running && (mr=vm_checkrange(proc_addr(who_p), pr, start, length, wr, 0)) != OK) { \ + return mr; \ + } } + +#define CHECKRANGE(pr, start, length, wr) \ + vm_checkrange(proc_addr(who_p), pr, start, length, wr, 1) + +/* Pseudo error code indicating a process request has to be + * restarted after an OK from VM. + */ +#define VMSUSPEND -996 + +#endif + + diff --git a/lib/other/Makefile.in b/lib/other/Makefile.in index 2bf999a22..61f6c87ad 100644 --- a/lib/other/Makefile.in +++ b/lib/other/Makefile.in @@ -27,6 +27,7 @@ libc_FILES=" \ _sprofile.c \ _svrctl.c \ _sysuname.c \ + _vm_dmacalls.c \ asynchio.c \ basename.c \ bcmp.c \ diff --git a/lib/other/_getnprocnr.c b/lib/other/_getnprocnr.c index 0dde28922..d86813cb2 100644 --- a/lib/other/_getnprocnr.c +++ b/lib/other/_getnprocnr.c @@ -6,9 +6,10 @@ PUBLIC int getnprocnr(pid_t pid) { message m; + int t = GETPROCNR; m.m1_i1 = pid; /* pass pid >=0 to search for */ m.m1_i2 = 0; /* don't pass name to search for */ - if (_syscall(PM_PROC_NR, GETPROCNR, &m) < 0) return(-1); + if (_syscall(PM_PROC_NR, t, &m) < 0) return(-1); return(m.m1_i1); /* return search result */ } diff --git a/lib/other/_vm_dmacalls.c b/lib/other/_vm_dmacalls.c new file mode 100644 index 000000000..17234088b --- /dev/null +++ b/lib/other/_vm_dmacalls.c @@ -0,0 +1,62 @@ + +#include +#define vm_adddma _vm_adddma +#define vm_deldma _vm_deldma +#define vm_getdma _vm_getdma +#include +#include +#include + +int vm_adddma(req_proc_e, proc_e, start, size) +endpoint_t req_proc_e; +endpoint_t proc_e; +phys_bytes start; +phys_bytes size; +{ + message m; + + m.VMAD_REQ= req_proc_e; + m.VMAD_EP= proc_e; + m.VMAD_START= start; + m.VMAD_SIZE= size; + + return _syscall(VM_PROC_NR, VM_ADDDMA, &m); +} + +int vm_deldma(req_proc_e, proc_e, start, size) +endpoint_t req_proc_e; +endpoint_t proc_e; +phys_bytes start; +phys_bytes size; +{ + message m; + + m.VMDD_REQ= proc_e; + m.VMDD_EP= proc_e; + m.VMDD_START= start; + m.VMDD_SIZE= size; + + return _syscall(VM_PROC_NR, VM_DELDMA, &m); +} + +int vm_getdma(req_proc_e, procp, basep, sizep) +endpoint_t req_proc_e; +endpoint_t *procp; +phys_bytes *basep; +phys_bytes *sizep; +{ + int r; + message m; + + m.VMGD_REQ = req_proc_e; + + r= _syscall(VM_PROC_NR, VM_GETDMA, &m); + if (r == 0) + { + *procp= m.VMGD_PROCP; + *basep= m.VMGD_BASEP; + *sizep= m.VMGD_SIZEP; + } + return r; +} + diff --git a/lib/posix/Makefile.in b/lib/posix/Makefile.in index 21c313f12..1e2bee8b3 100644 --- a/lib/posix/Makefile.in +++ b/lib/posix/Makefile.in @@ -55,6 +55,7 @@ libc_FILES=" \ _mkfifo.c \ _mknod.c \ _mount.c \ + _mmap.c \ _open.c \ _opendir.c \ _pathconf.c \ @@ -101,6 +102,7 @@ libc_FILES=" \ getloadavg.c \ getopt.c \ gettimeofday.c \ + glob.c \ nice.c \ priority.c \ usleep.c" diff --git a/lib/posix/_mmap.c b/lib/posix/_mmap.c new file mode 100755 index 000000000..4dbbbc8a3 --- /dev/null +++ b/lib/posix/_mmap.c @@ -0,0 +1,40 @@ +#define _SYSTEM 1 +#include +#define mmap _mmap +#define munmap _munmap +#include +#include +#include +#include + +PUBLIC void *mmap(void *addr, size_t len, int prot, int flags, + int fd, off_t offset) +{ + message m; + int r; + + m.VMM_ADDR = (vir_bytes) addr; + m.VMM_LEN = len; + m.VMM_PROT = prot; + m.VMM_FLAGS = flags; + m.VMM_FD = fd; + m.VMM_OFFSET = offset; + + r = _syscall(VM_PROC_NR, VM_MMAP, &m); + + if(r != OK) { + return MAP_FAILED; + } + + return (void *) m.VMM_RETADDR; +} + +PUBLIC int munmap(void *addr, size_t len) +{ + message m; + + m.VMUM_ADDR = addr; + m.VMUM_LEN = len; + + return _syscall(VM_PROC_NR, VM_UNMAP, &m); +} diff --git a/lib/posix/getloadavg.c b/lib/posix/getloadavg.c index 2d6976d19..82fceba1c 100755 --- a/lib/posix/getloadavg.c +++ b/lib/posix/getloadavg.c @@ -28,7 +28,7 @@ int getloadavg(double *loadavg, int nelem) nelem = PERIODS; /* How many ticks are missing from the newest-filled slot? */ -#define TICKSPERSLOT (_LOAD_UNIT_SECS * HZ) +#define TICKSPERSLOT (_LOAD_UNIT_SECS * sys_hz()) unfilled_ticks = TICKSPERSLOT - (loadinfo.last_clock % TICKSPERSLOT); for(p = 0; p < nelem; p++) { diff --git a/lib/stdtime/Makefile.in b/lib/stdtime/Makefile.in index ea657d580..3efdcb255 100644 --- a/lib/stdtime/Makefile.in +++ b/lib/stdtime/Makefile.in @@ -2,7 +2,7 @@ Z=../../commands/zoneinfo -CFLAGS="-O -D_MINIX -D_POSIX_SOURCE -D__USG -I$Z" +CFLAGS="-D_MINIX -D_POSIX_SOURCE -D__USG -I$Z" LIBRARIES=libc libc_FILES=" diff --git a/lib/syscall/Makefile.in b/lib/syscall/Makefile.in index 7ccfc22fd..403883f38 100644 --- a/lib/syscall/Makefile.in +++ b/lib/syscall/Makefile.in @@ -67,6 +67,7 @@ libc_FILES=" \ mkdir.s \ mkfifo.s \ mknod.s \ + mmap.s \ mount.s \ open.s \ opendir.s \ @@ -119,6 +120,7 @@ libc_FILES=" \ uname.s \ unlink.s \ utime.s \ + vm_dmacalls.s \ wait.s \ waitpid.s \ write.s" diff --git a/lib/syscall/mmap.s b/lib/syscall/mmap.s new file mode 100755 index 000000000..60664320f --- /dev/null +++ b/lib/syscall/mmap.s @@ -0,0 +1,7 @@ +.sect .text +.extern __mmap +.define _mmap +.align 2 + +_mmap: + jmp __mmap diff --git a/lib/syscall/vm_dmacalls.s b/lib/syscall/vm_dmacalls.s new file mode 100644 index 000000000..920af0d17 --- /dev/null +++ b/lib/syscall/vm_dmacalls.s @@ -0,0 +1,16 @@ +.sect .text +.extern __vm_adddma +.define _vm_adddma +.extern __vm_deldma +.define _vm_deldma +.extern __vm_getdma +.define _vm_getdma +.align 2 + +_vm_adddma: + jmp __vm_adddma +_vm_deldma: + jmp __vm_deldma +_vm_getdma: + jmp __vm_getdma + diff --git a/lib/syslib/Makefile.in b/lib/syslib/Makefile.in index 2a33f6e66..76d246b04 100644 --- a/lib/syslib/Makefile.in +++ b/lib/syslib/Makefile.in @@ -5,6 +5,7 @@ CFLAGS="-O -D_MINIX -D_POSIX_SOURCE" LIBRARIES=libsys libsys_FILES=" \ + alloc_util.c \ assert.c \ panic.c \ pci_attr_r16.c \ @@ -64,12 +65,20 @@ libsys_FILES=" \ sys_vinl.c \ sys_vinw.c \ sys_vircopy.c \ - sys_vm_map.c \ sys_vm_setbuf.c \ + sys_vmctl.c \ sys_voutb.c \ sys_voutl.c \ sys_voutw.c \ taskcall.c \ - ds.c" + ds.c \ + vm_allocmem.c \ + vm_brk.c \ + vm_exec_newmem.c \ + vm_exit.c \ + vm_fork.c \ + vm_map_phys.c \ + vm_umap.c \ + vm_push_sig.c" TYPE=both diff --git a/lib/syslib/alloc_util.c b/lib/syslib/alloc_util.c new file mode 100644 index 000000000..269b3b43a --- /dev/null +++ b/lib/syslib/alloc_util.c @@ -0,0 +1,69 @@ + +#include "syslib.h" + +#include +#include +#include +#include + +int sys_umap_data_fb(endpoint_t ep, vir_bytes buf, vir_bytes len, phys_bytes *phys) +{ + int r; + + if((r=sys_umap(ep, VM_D, buf, len, phys)) != OK) { + if(r != EINVAL) + return r; + r = sys_umap(ep, D, buf, len, phys); + } + + + return r; +} + + +void *alloc_contig(size_t len, int flags, phys_bytes *phys) +{ + int r; + vir_bytes buf; + int mmapflags = MAP_PREALLOC|MAP_CONTIG|MAP_ANON; + + if(flags & AC_LOWER16M) + mmapflags |= MAP_LOWER16M; + + /* First try to get memory with mmap. This is gauranteed + * to be page-aligned, and we can tell VM it has to be + * pre-allocated and contiguous. + */ + errno = 0; + buf = (vir_bytes) mmap(0, len, PROT_READ|PROT_WRITE, mmapflags, -1, 0); + + /* If that failed, maybe we're not running in paged mode. + * If that's the case, ENXIO will be returned. + * Memory returned with malloc() will be preallocated and + * contiguous, so fallback on that, and ask for a little extra + * so we can page align it ourselves. + */ + if(buf == (vir_bytes) MAP_FAILED) { + if(errno != (_SIGN ENXIO)) { + return NULL; + } +#define ALIGN 4096 + if(flags & AC_ALIGN4K) { + if(len + ALIGN < len) + return NULL; + len += ALIGN; + } + if(!(buf = (vir_bytes) malloc(len))) { + return NULL; + } + if(flags & AC_ALIGN4K) + buf += ALIGN - (buf % ALIGN); + } + + /* Get physical address. */ + if(sys_umap_data_fb(SELF, buf, len, phys) != OK) + panic("alloc_contig.c", "sys_umap_data_fb failed", NO_NUM); + + return (void *) buf; +} + diff --git a/lib/syslib/ds.c b/lib/syslib/ds.c index d2b369641..833fd943e 100644 --- a/lib/syslib/ds.c +++ b/lib/syslib/ds.c @@ -4,6 +4,8 @@ #include "syslib.h" +#define GRANTBAD -1001 + int ds_subscribe(ds_name_regexp, type, flags) char *ds_name_regexp; @@ -20,7 +22,7 @@ int flags; (vir_bytes) ds_name_regexp, len, CPF_READ); if(!GRANT_VALID(g)) - return -1; + return GRANTBAD; flags &= DS_INITIAL; @@ -49,7 +51,7 @@ u32_t value; (vir_bytes) ds_name, len, CPF_READ); if(!GRANT_VALID(g)) - return -1; + return GRANTBAD; m.DS_KEY_GRANT = (char *) g; m.DS_KEY_LEN = len; @@ -78,7 +80,7 @@ char *value; g_key = cpf_grant_direct(DS_PROC_NR, (vir_bytes) ds_name, len_key, CPF_READ); if(!GRANT_VALID(g_key)) - return -1; + return GRANTBAD; /* Grant for value. */ len_str = strlen(value)+1; @@ -87,7 +89,7 @@ char *value; if(!GRANT_VALID(g_str)) { cpf_revoke(g_key); - return -1; + return GRANTBAD; } m.DS_KEY_GRANT = (char *) g_key; @@ -118,7 +120,7 @@ u32_t *value; g_key = cpf_grant_direct(DS_PROC_NR, (vir_bytes) ds_name, len_key, CPF_READ); if(!GRANT_VALID(g_key)) - return -1; + return GRANTBAD; /* Do request. */ m.DS_KEY_GRANT = (char *) g_key; @@ -150,7 +152,7 @@ size_t len_str; g_key = cpf_grant_direct(DS_PROC_NR, (vir_bytes) ds_name, len_key, CPF_READ); if(!GRANT_VALID(g_key)) - return -1; + return GRANTBAD; /* Grant for value. */ g_str = cpf_grant_direct(DS_PROC_NR, @@ -158,7 +160,7 @@ size_t len_str; if(!GRANT_VALID(g_str)) { cpf_revoke(g_key); - return -1; + return GRANTBAD; } /* Do request. */ @@ -187,13 +189,13 @@ size_t len_str; message m; cp_grant_id_t g_key, g_str; - if(len_key < 1 || len_str < 1) return -1; + if(len_key < 1 || len_str < 1) return -1002; /* Grant for key. */ g_key = cpf_grant_direct(DS_PROC_NR, (vir_bytes) ds_key, len_key, CPF_WRITE); if(!GRANT_VALID(g_key)) - return -1; + return GRANTBAD; /* Grant for value. */ g_str = cpf_grant_direct(DS_PROC_NR, @@ -201,7 +203,7 @@ size_t len_str; if(!GRANT_VALID(g_str)) { cpf_revoke(g_key); - return -1; + return GRANTBAD; } /* Do request. */ @@ -238,7 +240,7 @@ u32_t *value; g_key = cpf_grant_direct(DS_PROC_NR, (vir_bytes) ds_key, len_key, CPF_WRITE); if(!GRANT_VALID(g_key)) - return -1; + return GRANTBAD; /* Do request. */ m.DS_KEY_GRANT = (char *) g_key; diff --git a/lib/syslib/panic.c b/lib/syslib/panic.c index 89d3a41ac..a40cab8ae 100644 --- a/lib/syslib/panic.c +++ b/lib/syslib/panic.c @@ -19,9 +19,19 @@ int num; /* number to go with format string */ * value of a defined constant. */ message m; + endpoint_t me = NONE; + char name[20]; void (*suicide)(void); - + if(panicing) return; panicing= 1; + + if(sys_whoami(&me, name, sizeof(name)) == OK && me != NONE) + printf("%s(%d): ", name, me); + else + printf("(sys_whoami failed): "); + printf("syslib:panic.c: stacktrace: "); + util_stacktrace(); + if (NULL != who && NULL != mess) { if (num != NO_NUM) { printf("Panic in %s: %s: %d\n", who, mess, num); @@ -39,12 +49,10 @@ int num; /* number to go with format string */ /* If exiting nicely through PM fails for some reason, try to * commit suicide. E.g., message to PM might fail due to deadlock. */ - printf("panic: trying exception\n"); suicide = (void (*)(void)) -1; suicide(); /* If committing suicide fails for some reason, hang. */ - printf("panic: for ever and ever\n"); for(;;) { } } diff --git a/lib/syslib/safecopies.c b/lib/syslib/safecopies.c index 845afc451..d09a789e5 100644 --- a/lib/syslib/safecopies.c +++ b/lib/syslib/safecopies.c @@ -52,8 +52,9 @@ cpf_grow(void) assert(new_size > ngrants); /* Allocate a block of new size. */ - if(!(new_grants=malloc(new_size * sizeof(grants[0])))) + if(!(new_grants=malloc(new_size * sizeof(grants[0])))) { return; + } /* Copy old block to new block. */ if(grants && ngrants > 0) diff --git a/lib/syslib/sys_fork.c b/lib/syslib/sys_fork.c index fb0117d5f..8aef1b8ca 100755 --- a/lib/syslib/sys_fork.c +++ b/lib/syslib/sys_fork.c @@ -1,10 +1,11 @@ #include "syslib.h" -PUBLIC int sys_fork(parent, child, child_endpoint, map_ptr) -int parent; /* process doing the fork */ -int child; /* which proc has been created by the fork */ +PUBLIC int sys_fork(parent, child, child_endpoint, map_ptr, flags) +endpoint_t parent; /* process doing the fork */ +endpoint_t child; /* which proc has been created by the fork */ int *child_endpoint; struct mem_map *map_ptr; +u32_t flags; { /* A process has forked. Tell the kernel. */ @@ -14,6 +15,7 @@ struct mem_map *map_ptr; m.PR_ENDPT = parent; m.PR_SLOT = child; m.PR_MEM_PTR = (char *) map_ptr; + m.PR_FORK_FLAGS = flags; r = _taskcall(SYSTASK, SYS_FORK, &m); *child_endpoint = m.PR_ENDPT; return r; diff --git a/lib/syslib/sys_getinfo.c b/lib/syslib/sys_getinfo.c index dd4bc43b9..b712c6bee 100644 --- a/lib/syslib/sys_getinfo.c +++ b/lib/syslib/sys_getinfo.c @@ -1,3 +1,6 @@ + +#include + #include "syslib.h" /*===========================================================================* @@ -22,4 +25,29 @@ int len2; /* length or process nr */ return(_taskcall(SYSTASK, SYS_GETINFO, &m)); } +/*===========================================================================* + * sys_whoami * + *===========================================================================*/ +PUBLIC int sys_whoami(endpoint_t *who_ep, char *who_name, int len) +{ + message m; + int r; + int lenmin; + + m.I_REQUEST = GET_WHOAMI; + + if(len < 2) + return EINVAL; + + if((r = _taskcall(SYSTASK, SYS_GETINFO, &m)) != OK) + return r; + + lenmin = MIN(len, sizeof(m.GIWHO_NAME)) - 1; + + strncpy(who_name, m.GIWHO_NAME, lenmin); + who_name[lenmin] = '\0'; + *who_ep = m.GIWHO_EP; + + return OK; +} diff --git a/lib/syslib/sys_vm_map.c b/lib/syslib/sys_vm_map.c deleted file mode 100644 index 6f4296da1..000000000 --- a/lib/syslib/sys_vm_map.c +++ /dev/null @@ -1,25 +0,0 @@ -#include "syslib.h" - -/*===========================================================================* - * sys_vm_map * - *===========================================================================*/ -PUBLIC int sys_vm_map(proc_nr, do_map, base, size, offset) -int proc_nr; -int do_map; -phys_bytes base; -phys_bytes size; -phys_bytes offset; -{ - message m; - int result; - - m.m4_l1= proc_nr; - m.m4_l2= do_map; - m.m4_l3= base; - m.m4_l4= size; - m.m4_l5= offset; - - result = _taskcall(SYSTASK, SYS_VM_MAP, &m); - return(result); -} - diff --git a/lib/syslib/sys_vmctl.c b/lib/syslib/sys_vmctl.c new file mode 100755 index 000000000..8339a73a9 --- /dev/null +++ b/lib/syslib/sys_vmctl.c @@ -0,0 +1,61 @@ +#include "syslib.h" + +PUBLIC int sys_vmctl(endpoint_t who, int param, u32_t value) +{ + message m; + int r; + + m.SVMCTL_WHO = who; + m.SVMCTL_PARAM = param; + m.SVMCTL_VALUE = value; + r = _taskcall(SYSTASK, SYS_VMCTL, &m); + return(r); +} + +PUBLIC int sys_vmctl_get_pagefault_i386(endpoint_t *who, u32_t *cr2, u32_t *err) +{ + message m; + int r; + + m.SVMCTL_WHO = SELF; + m.SVMCTL_PARAM = VMCTL_GET_PAGEFAULT; + r = _taskcall(SYSTASK, SYS_VMCTL, &m); + if(r == OK) { + *who = m.SVMCTL_PF_WHO; + *cr2 = m.SVMCTL_PF_I386_CR2; + *err = m.SVMCTL_PF_I386_ERR; + } + return(r); +} + +PUBLIC int sys_vmctl_get_cr3_i386(endpoint_t who, u32_t *cr3) +{ + message m; + int r; + + m.SVMCTL_WHO = who; + m.SVMCTL_PARAM = VMCTL_I386_GETCR3; + r = _taskcall(SYSTASK, SYS_VMCTL, &m); + if(r == OK) { + *cr3 = m.SVMCTL_VALUE; + } + return(r); +} + +PUBLIC int sys_vmctl_get_memreq(endpoint_t *who, vir_bytes *mem, + vir_bytes *len, int *wrflag) +{ + message m; + int r; + + m.SVMCTL_WHO = SELF; + m.SVMCTL_PARAM = VMCTL_MEMREQ_GET; + r = _taskcall(SYSTASK, SYS_VMCTL, &m); + if(r == OK) { + *who = m.SVMCTL_MRG_EP; + *mem = (vir_bytes) m.SVMCTL_MRG_ADDR; + *len = m.SVMCTL_MRG_LEN; + *wrflag = m.SVMCTL_MRG_WRITE; + } + return r; +} diff --git a/lib/syslib/vm_allocmem.c b/lib/syslib/vm_allocmem.c new file mode 100644 index 000000000..64e1a791d --- /dev/null +++ b/lib/syslib/vm_allocmem.c @@ -0,0 +1,21 @@ + +#include "syslib.h" + +#include + +/*===========================================================================* + * vm_allocmem * + *===========================================================================*/ +PUBLIC int vm_allocmem(phys_clicks clicks, phys_clicks *retmembase) +{ + message m; + int result; + + m.VMAM_CLICKS = clicks; + result = _taskcall(VM_PROC_NR, VM_ALLOCMEM, &m); + if(result == OK) + *retmembase = m.VMAM_MEMBASE; + + return result; +} + diff --git a/lib/syslib/vm_brk.c b/lib/syslib/vm_brk.c new file mode 100644 index 000000000..f17da63f7 --- /dev/null +++ b/lib/syslib/vm_brk.c @@ -0,0 +1,19 @@ + +#include "syslib.h" + +#include + +/*===========================================================================* + * vm_brk * + *===========================================================================*/ +PUBLIC int vm_brk(endpoint_t ep, char *addr) +{ + message m; + int result; + + m.VMB_ENDPOINT = ep; + m.VMB_ADDR = (void *) addr; + + return _taskcall(VM_PROC_NR, VM_BRK, &m); +} + diff --git a/lib/syslib/vm_exec_newmem.c b/lib/syslib/vm_exec_newmem.c new file mode 100644 index 000000000..3f1394771 --- /dev/null +++ b/lib/syslib/vm_exec_newmem.c @@ -0,0 +1,26 @@ + +#include "syslib.h" + +#include + +/*===========================================================================* + * vm_exec_newmem * + *===========================================================================*/ +PUBLIC int vm_exec_newmem(endpoint_t ep, struct exec_newmem *args, + int argssize, char **ret_stack_top, int *ret_flags) +{ + message m; + int result; + + m.VMEN_ENDPOINT = ep; + m.VMEN_ARGSPTR = (void *) args; + m.VMEN_ARGSSIZE = argssize; + + result = _taskcall(VM_PROC_NR, VM_EXEC_NEWMEM, &m); + + *ret_stack_top = m.VMEN_STACK_TOP; + *ret_flags = m.VMEN_FLAGS; + + return result; +} + diff --git a/lib/syslib/vm_exit.c b/lib/syslib/vm_exit.c new file mode 100644 index 000000000..77500b239 --- /dev/null +++ b/lib/syslib/vm_exit.c @@ -0,0 +1,34 @@ + +#include "syslib.h" + +#include + +/*===========================================================================* + * vm_exit * + *===========================================================================*/ +PUBLIC int vm_exit(endpoint_t ep) +{ + message m; + int result; + + m.VME_ENDPOINT = ep; + + result = _taskcall(VM_PROC_NR, VM_EXIT, &m); + return(result); +} + + +/*===========================================================================* + * vm_willexit * + *===========================================================================*/ +PUBLIC int vm_willexit(endpoint_t ep) +{ + message m; + int result; + + m.VMWE_ENDPOINT = ep; + + result = _taskcall(VM_PROC_NR, VM_WILLEXIT, &m); + return(result); +} + diff --git a/lib/syslib/vm_fork.c b/lib/syslib/vm_fork.c new file mode 100644 index 000000000..c67e2cb70 --- /dev/null +++ b/lib/syslib/vm_fork.c @@ -0,0 +1,23 @@ + +#include "syslib.h" + +#include + +/*===========================================================================* + * vm_fork * + *===========================================================================*/ +PUBLIC int vm_fork(endpoint_t ep, int slot, int *childep) +{ + message m; + int result; + + m.VMF_ENDPOINT = ep; + m.VMF_SLOTNO = slot; + + result = _taskcall(VM_PROC_NR, VM_FORK, &m); + + *childep = m.VMF_CHILD_ENDPOINT; + + return(result); +} + diff --git a/lib/syslib/vm_map_phys.c b/lib/syslib/vm_map_phys.c new file mode 100644 index 000000000..5eef16186 --- /dev/null +++ b/lib/syslib/vm_map_phys.c @@ -0,0 +1,37 @@ +#define _SYSTEM 1 +#include +#define vm_map_phys _vm_map_phys +#define vm_unmap_phys _vm_unmap_phys +#include +#include +#include +#include +#include + +PUBLIC void *vm_map_phys(endpoint_t who, size_t len, void *phaddr) +{ + message m; + int r; + + m.VMMP_EP = who; + m.VMMP_PHADDR = phaddr; + m.VMMP_LEN = len; + + r = _syscall(VM_PROC_NR, VM_MAP_PHYS, &m); + + if(r != OK) return MAP_FAILED; + + return (void *) m.VMMP_VADDR_REPLY; +} + +PUBLIC int vm_unmap_phys(endpoint_t who, void *vaddr, size_t len) +{ + message m; + int r; + + m.VMUP_EP = who; + m.VMUP_VADDR = vaddr; + + return _syscall(VM_PROC_NR, VM_UNMAP_PHYS, &m); +} + diff --git a/lib/syslib/vm_push_sig.c b/lib/syslib/vm_push_sig.c new file mode 100644 index 000000000..1f994e537 --- /dev/null +++ b/lib/syslib/vm_push_sig.c @@ -0,0 +1,20 @@ + +#include "syslib.h" + +#include + +/*===========================================================================* + * vm_push_sig * + *===========================================================================*/ +PUBLIC int vm_push_sig(endpoint_t ep, vir_bytes *old_sp) +{ + message m; + int result; + + m.VMPS_ENDPOINT = ep; + result = _taskcall(VM_PROC_NR, VM_PUSH_SIG, &m); + *old_sp = (vir_bytes) m.VMPS_OLD_SP; + + return result; +} + diff --git a/lib/syslib/vm_umap.c b/lib/syslib/vm_umap.c new file mode 100644 index 000000000..73db2fc0d --- /dev/null +++ b/lib/syslib/vm_umap.c @@ -0,0 +1,22 @@ + +#include "syslib.h" + +#include + +/*===========================================================================* + * vm_umap * + *===========================================================================*/ +PUBLIC int vm_umap(int seg, vir_bytes offset, vir_bytes len, phys_bytes *addr) +{ + message m; + int result; + + m.VMU_SEG = seg; + m.VMU_OFFSET = offset; + m.VMU_LENGTH = len; + result = _taskcall(VM_PROC_NR, VM_UMAP, &m); + *addr = m.VMU_RETADDR; + + return result; +} + diff --git a/lib/sysutil/Makefile.in b/lib/sysutil/Makefile.in index 74717497e..3082a1909 100644 --- a/lib/sysutil/Makefile.in +++ b/lib/sysutil/Makefile.in @@ -1,10 +1,11 @@ -# Makefile for lib/utils. +# Makefile for lib/sysutil. CFLAGS="-O -D_MINIX -D_POSIX_SOURCE" -LIBRARIES=libsysutil +LIBRARIES=libsys -libsysutil_FILES=" \ +libsys_FILES=" \ + asynsend.c \ kmalloc.c \ kprintf.c \ kputc.c \ @@ -21,6 +22,8 @@ libsysutil_FILES=" \ taskcall.c \ read_tsc.s \ read_tsc_64.c \ + stacktrace.c \ + sys_hz.c \ profile_extern.c \ profile.c" diff --git a/lib/sysutil/kputc.c b/lib/sysutil/kputc.c index 47309b50e..9f22547da 100644 --- a/lib/sysutil/kputc.c +++ b/lib/sysutil/kputc.c @@ -9,7 +9,7 @@ #include "sysutil.h" -static char print_buf[80]; /* output is buffered here */ +static char print_buf[80*25]; /* output is buffered here */ int kputc_use_private_grants= 0; @@ -56,15 +56,22 @@ int c; for(p = 0; procs[p] != NONE; p++) { /* Send the buffer to this output driver. */ + int may_asyn = 0; m.DIAG_BUF_COUNT = buf_count; if(GRANT_VALID(printgrants[p])) { m.m_type = DIAGNOSTICS_S; m.DIAG_PRINT_BUF_G = (char *) printgrants[p]; + may_asyn = 1; } else { m.m_type = DIAGNOSTICS; m.DIAG_PRINT_BUF_G = print_buf; } - (void) _sendrec(procs[p], &m); + if(may_asyn && procs[p] == LOG_PROC_NR) { + m.m_type = ASYN_DIAGNOSTICS; + (void) asynsend(procs[p], &m); + } else { + sendrec(procs[p], &m); + } } buf_count = 0; diff --git a/lib/sysutil/micro_delay.c b/lib/sysutil/micro_delay.c index 9789bfd81..773897943 100644 --- a/lib/sysutil/micro_delay.c +++ b/lib/sysutil/micro_delay.c @@ -10,20 +10,31 @@ #include "sysutil.h" -#define CALIBRATE_TICKS (HZ/5) +#define CALIBRATE_TICKS(h) ((h)/5) #define MICROHZ 1000000 /* number of micros per second */ -#define MICROSPERTICK (MICROHZ/HZ) /* number of micros per HZ tick */ +#define MICROSPERTICK(h) (MICROHZ/(h)) /* number of micros per HZ tick */ -static u32_t calib_tsc; +#define CALIBRATE \ + if(!calibrated) { \ + int r; \ + if((r=micro_delay_calibrate()) != OK) \ + panic(__FILE__, "micro_delay: calibrate failed\n", r); \ + } + +static u32_t calib_tsc, Hz = 0; static int calibrated = 0; int micro_delay_calibrate(void) { - u64_t start, end, diff, hz; + u64_t start, end, diff; struct tms tms; unsigned long t = 0; + /* Get HZ. */ + if(sys_getinfo(GET_HZ, &Hz, sizeof(Hz), 0, 0) != OK) + Hz = HZ; + /* Wait for clock to tick. */ while(!t || (t == times(&tms))) t = times(&tms); @@ -34,7 +45,7 @@ micro_delay_calibrate(void) * this using the TSC. */ read_tsc_64(&start); - while(times(&tms) < t+CALIBRATE_TICKS) ; + while(times(&tms) < t+CALIBRATE_TICKS(Hz)) ; read_tsc_64(&end); diff = sub64(end, start); @@ -43,10 +54,12 @@ micro_delay_calibrate(void) "micro_delay_calibrate: CALIBRATE_TICKS too high " "for TSC frequency\n", NO_NUM); calib_tsc = ex64lo(diff); +#if 0 printf("micro_delay_calibrate: " "%lu cycles/%d ticks of %d Hz; %lu cycles/s\n", - calib_tsc, CALIBRATE_TICKS, HZ, - div64u(mul64u(calib_tsc, HZ), CALIBRATE_TICKS)); + calib_tsc, CALIBRATE_TICKS(Hz), Hz, + div64u(mul64u(calib_tsc, Hz), CALIBRATE_TICKS(Hz))); +#endif calibrated = 1; return OK; @@ -60,17 +73,11 @@ micro_delay(u32_t micros) /* Start of delay. */ read_tsc_64(&now); - /* We have to be calibrated. */ - if(!calibrated) { - int r; - printf("micro_delay: calibrating\n"); - if((r=micro_delay_calibrate()) != OK) - panic(__FILE__, "micro_delay: calibrate failed\n", r); - } + CALIBRATE; /* We have to know when to end the delay. */ end = add64u(now, div64u(mul64u(calib_tsc, - micros * HZ / CALIBRATE_TICKS), MICROHZ)); + micros * Hz / CALIBRATE_TICKS(Hz)), MICROHZ)); /* If we have to wait for at least one HZ tick, use the regular * tickdelay first. Round downwards on purpose, so the average @@ -78,8 +85,8 @@ micro_delay(u32_t micros) * we call tickdelay). We can correct for both overhead of tickdelay * itself and the short wait in the busywait later. */ - if(micros >= MICROSPERTICK) - tickdelay(micros*HZ/MICROHZ); + if(micros >= MICROSPERTICK(Hz)) + tickdelay(micros*Hz/MICROHZ); /* Wait (the rest) of the delay time using busywait. */ while(cmp64(now, end) < 0) @@ -87,3 +94,4 @@ micro_delay(u32_t micros) return OK; } + diff --git a/lib/sysutil/stacktrace.c b/lib/sysutil/stacktrace.c new file mode 100644 index 000000000..377215de7 --- /dev/null +++ b/lib/sysutil/stacktrace.c @@ -0,0 +1,63 @@ +/* +stacktrace.c + +Created: Jan 19, 1993 by Philip Homburg + +Copyright 1995 Philip Homburg +*/ + +typedef unsigned int reg_t; + +#define FUNC_STACKTRACE(statement) \ +{ \ + reg_t bp, pc, hbp; \ + extern reg_t get_bp(void); \ + \ + bp= get_bp(); \ + while(bp) \ + { \ + pc= ((reg_t *)bp)[1]; \ + hbp= ((reg_t *)bp)[0]; \ + statement; \ + if (hbp != 0 && hbp <= bp) \ + { \ + pc = -1; \ + statement; \ + break; \ + } \ + bp= hbp; \ + } \ +} + +void util_nstrcat(char *str, unsigned long number) +{ + int n = 10, lead = 1; + char nbuf[12], *p; + p = nbuf; + *p++ = '0'; + *p++ = 'x'; + for(n = 0; n < 8; n++) { + int i; + i = (number >> ((7-n)*4)) & 0xF; + if(!lead || i) { + *p++ = i < 10 ? '0' + i : 'a' + i - 10; + lead = 0; + } + } + if(lead) *p++ = '0'; + *p++ = ' '; + *p++ = '\0'; + strcat(str, nbuf); +} + +void util_stacktrace(void) +{ + FUNC_STACKTRACE(printf("0x%lx ", (unsigned long) pc)); + printf("\n"); +} + +void util_stacktrace_strcat(char *str) +{ + FUNC_STACKTRACE(util_nstrcat(str, pc)); +} + diff --git a/lib/sysutil/sys_hz.c b/lib/sysutil/sys_hz.c new file mode 100644 index 000000000..10130175e --- /dev/null +++ b/lib/sysutil/sys_hz.c @@ -0,0 +1,41 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sysutil.h" + +static u32_t Hz; + +u32_t +sys_hz(void) +{ + if(Hz <= 0) { + int r; + /* Get HZ. */ + if((r=sys_getinfo(GET_HZ, &Hz, sizeof(Hz), 0, 0)) != OK) { + Hz = HZ; + printf("sys_hz: %d: reverting to HZ = %d\n", r, Hz); + } + } + + return Hz; +} + +u32_t +micros_to_ticks(u32_t micros) +{ + u32_t ticks; + + ticks = div64u(mul64u(micros, sys_hz()), 1000000); + if(ticks < 1) ticks = 1; + + return ticks; +} + + diff --git a/servers/Makefile b/servers/Makefile index a534e5686..8316c7405 100644 --- a/servers/Makefile +++ b/servers/Makefile @@ -21,6 +21,7 @@ all install depend clean: cd ./rs && $(MAKE) $@ cd ./ds && $(MAKE) $@ cd ./is && $(MAKE) $@ + cd ./vm && $(MAKE) $@ cd ./init && $(MAKE) $@ cd ./inet && $(MAKE) $@ @@ -30,6 +31,6 @@ image: cd ./mfs && $(MAKE) EXTRA_OPTS=$(EXTRA_OPTS) build cd ./rs && $(MAKE) EXTRA_OPTS=$(EXTRA_OPTS) build cd ./ds && $(MAKE) EXTRA_OPTS=$(EXTRA_OPTS) build + cd ./vm && $(MAKE) EXTRA_OPTS=$(EXTRA_OPTS) build cd ./init && $(MAKE) EXTRA_OPTS=$(EXTRA_OPTS) build - diff --git a/servers/ds/Makefile b/servers/ds/Makefile index 9ea37eb75..b92f429df 100644 --- a/servers/ds/Makefile +++ b/servers/ds/Makefile @@ -15,7 +15,7 @@ f = $u/src/servers/fs CC = exec cc CFLAGS = -I$i $(CPROFILE) LDFLAGS = -i -LIBS = -lsysutil -lsys +LIBS = -lsys OBJ = main.o store.o @@ -27,8 +27,6 @@ $(SERVER): $(OBJ) # install with other servers install: $(SERVER) - install -o root -c $? /sbin/$(SERVER) -# install -o root -cs $? $@ # clean up local files clean: diff --git a/servers/inet/Makefile b/servers/inet/Makefile index c2e6559e5..2a8c65c66 100644 --- a/servers/inet/Makefile +++ b/servers/inet/Makefile @@ -8,7 +8,7 @@ CC = cc CPPFLAGS = -I. -D_MINIX CFLAGS = $(OPT) $(CPPFLAGS) $(CPROFILE) LDFLAGS = -LIBS = -lsysutil -lsys +LIBS = -lsys .c.o: $(CC) $(CFLAGS) -o $@ -c $< @@ -29,7 +29,7 @@ inet: $(OBJ) $(CC) -o $@ $(LDFLAGS) $(OBJ) version.c $(LIBS) install: inet - install -c $? /usr/sbin/inet + install -c $< /usr/sbin/inet clean: rm -f $(OBJ) inet *.bak diff --git a/servers/inet/generic/eth.c b/servers/inet/generic/eth.c index 8d132ba0e..fba51879c 100644 --- a/servers/inet/generic/eth.c +++ b/servers/inet/generic/eth.c @@ -342,8 +342,10 @@ ioreq_t req; if (!(eth_port->etp_flags & EPF_GOT_ADDR)) { +#if 0 printf( "eth_ioctl: suspending NWIOGETHSTAT ioctl\n"); +#endif eth_fd->ef_ioctl_req= req; assert(!(eth_fd->ef_flags & EFF_IOCTL_IP)); @@ -372,14 +374,18 @@ ioreq_t req; ðstat->nwes_stat); if (result == SUSPEND) { +#if 0 printf( "eth_ioctl: eth_get_stat returned SUSPEND\n"); +#endif eth_fd->ef_ioctl_req= req; assert(!(eth_fd->ef_flags & EFF_IOCTL_IP)); eth_fd->ef_flags |= EFF_IOCTL_IP; +#if 0 printf("eth_ioctl: setting etp_getstat in port %d to %p\n", eth_port-eth_port_table, acc); +#endif eth_port->etp_getstat= acc; acc= NULL; return NW_SUSPEND; @@ -1049,7 +1055,9 @@ eth_port_t *eth_port; eth_fd_t *eth_fd; acc_t *acc; +#if 0 printf("in eth_restart_ioctl\n"); +#endif /* eth_restart_ioctl is called on too occasions: when a device * driver registers with inet and when a eth_get_stat call has @@ -1069,12 +1077,16 @@ eth_port_t *eth_port; if (eth_fd->ef_ioctl_req != NWIOGETHSTAT) continue; +#if 0 printf("eth_restart_ioctl: etp_getstat in port %d is %p\n", eth_port-eth_port_table, acc); +#endif if (acc != NULL) { +#if 0 printf("eth_restart_ioctl: completed getstat\n"); +#endif acc->acc_linkC++; r= (*eth_fd->ef_put_userdata)(eth_fd->ef_srfd, 0, acc, TRUE); @@ -1092,8 +1104,10 @@ printf("eth_restart_ioctl: etp_getstat in port %d is %p\n", if (acc != NULL) { +#if 0 printf("eth_restart_ioctl: clearing etp_getstat in port %d\n", eth_port-eth_port_table); +#endif assert(acc == eth_port->etp_getstat); bf_afree(acc); diff --git a/servers/inet/mnx_eth.c b/servers/inet/mnx_eth.c index 037bd7dc0..88d030681 100644 --- a/servers/inet/mnx_eth.c +++ b/servers/inet/mnx_eth.c @@ -34,7 +34,9 @@ FORWARD _PROTOTYPE( eth_port_t *find_port, (message *m) ); FORWARD _PROTOTYPE( void eth_restart, (eth_port_t *eth_port, int tasknr) ); FORWARD _PROTOTYPE( void send_getstat, (eth_port_t *eth_port) ); +#if 0 FORWARD _PROTOTYPE( int asynsend, (endpoint_t dst, message *mp) ); +#endif PUBLIC void osdep_eth_init() { @@ -339,7 +341,9 @@ message *m; if (!(loc_port->etp_flags & EPF_GOT_ADDR)) { loc_port->etp_flags |= EPF_GOT_ADDR; +#if 0 printf("eth_rec: calling eth_restart_ioctl\n"); +#endif eth_restart_ioctl(loc_port); /* Also update any VLANs on this device */ @@ -359,6 +363,7 @@ message *m; if (!(loc_port->etp_flags & EPF_READ_IP)) setup_read (loc_port); +#if 0 if (loc_port->etp_osdep.etp_flags & OEPF_NEED_SEND) { printf("eth_rec(conf): OEPF_NEED_SEND is set\n"); @@ -371,6 +376,7 @@ message *m; { printf("eth_rec(conf): OEPF_NEED_STAT is set\n"); } +#endif return; } @@ -404,6 +410,7 @@ message *m; assert(loc_port->etp_flags & EPF_GOT_ADDR); eth_restart_ioctl(loc_port); +#if 0 if (loc_port->etp_osdep.etp_flags & OEPF_NEED_SEND) { printf("eth_rec(stat): OEPF_NEED_SEND is set\n"); @@ -416,6 +423,8 @@ message *m; { printf("eth_rec(stat): OEPF_NEED_CONF is set\n"); } +#endif + #if 0 if (loc_port->etp_osdep.etp_state == OEPS_IDLE && (loc_port->etp_osdep.etp_flags & OEPF_NEED_CONF)) @@ -549,7 +558,9 @@ u32_t flags; if (!(eth_port->etp_flags & EPF_GOT_ADDR)) { /* We have never seen the device. */ +#if 0 printf("eth_set_rec_conf: waiting for device to appear\n"); +#endif return; } @@ -1002,6 +1013,7 @@ eth_port_t *eth_port; ip_panic(( "eth_get_stat: asynsend failed: %d", r)); } +#if 0 PRIVATE asynmsg_t *msgtable= NULL; PRIVATE size_t msgtable_n= 0; @@ -1050,6 +1062,7 @@ message *mp; /* Tell the kernel to rescan the table */ return senda(msgtable, msgtable_n); } +#endif /* * $PchId: mnx_eth.c,v 1.16 2005/06/28 14:24:37 philip Exp $ diff --git a/servers/init/Makefile b/servers/init/Makefile index 7eb05c74c..2ac270721 100644 --- a/servers/init/Makefile +++ b/servers/init/Makefile @@ -18,7 +18,7 @@ OBJ = init.o # build local binary all build: $(SERVER) $(SERVER): $(OBJ) - $(CC) $(CFLAGS) -o $@ $(LDFLAGS) $(OBJ) -lsysutil + $(CC) $(CFLAGS) -o $@ $(LDFLAGS) $(OBJ) -lsys install -S 8k $@ # install with other servers diff --git a/servers/is/Makefile b/servers/is/Makefile index 1ad889105..5edfab3ff 100644 --- a/servers/is/Makefile +++ b/servers/is/Makefile @@ -18,7 +18,7 @@ CC = exec cc CPPFLAGS=-I../../kernel/arch/$(ARCH)/include -I$i CFLAGS = $(CPROFILE) $(CPPFLAGS) LDFLAGS = -i -LIBS = -lsysutil -lsys +LIBS = -lsys OBJ = main.o dmp.o dmp_kernel.o dmp_pm.o dmp_fs.o dmp_rs.o dmp_ds.o @@ -30,7 +30,7 @@ $(SERVER): $(OBJ) # install with other servers install: $(SERVER) - install -o root -c $? /sbin/$(SERVER) + install -o root -c $< /sbin/$(SERVER) # clean up local files clean: diff --git a/servers/is/dmp.c b/servers/is/dmp.c index 483a9c51c..18405d1d2 100644 --- a/servers/is/dmp.c +++ b/servers/is/dmp.c @@ -35,7 +35,6 @@ struct hook_entry { { SF4, dtab_dmp, "Device/Driver mapping" }, { SF5, mapping_dmp, "Print key mappings" }, { SF6, rproc_dmp, "Reincarnation server process table" }, - { SF7, holes_dmp, "Memory free list" }, { SF8, data_store_dmp, "Data store contents" }, }; diff --git a/servers/is/dmp_kernel.c b/servers/is/dmp_kernel.c index f677ed4ee..1a0b4987d 100644 --- a/servers/is/dmp_kernel.c +++ b/servers/is/dmp_kernel.c @@ -12,6 +12,8 @@ #include "../../kernel/proc.h" #include "../../kernel/ipc.h" +#define LINES 22 + #define click_to_round_k(n) \ ((unsigned) ((((unsigned long) (n) << CLICK_SHIFT) + 512) / 1024)) @@ -34,9 +36,6 @@ PUBLIC struct boot_image image[NR_BOOT_PROCS]; *===========================================================================*/ PUBLIC void timing_dmp() { -#if ! DEBUG_TIME_LOCKS - printf("Enable the DEBUG_TIME_LOCKS definition in src/kernel/config.h\n"); -#else static struct lock_timingdata timingdata[TIMING_CATEGORIES]; int r, c, f, skipped = 0, printed = 0, maxlines = 23, x = 0; static int offsetlines = 0; @@ -66,7 +65,6 @@ PUBLIC void timing_dmp() } if (x > 0) printf("\n"); } -#endif } /*===========================================================================* @@ -75,7 +73,7 @@ PUBLIC void timing_dmp() PUBLIC void kmessages_dmp() { struct kmessages kmess; /* get copy of kernel messages */ - char print_buf[KMESS_BUF_SIZE+1]; /* this one is used to print */ + char print_buf[_KMESS_BUF_SIZE+1]; /* this one is used to print */ int start; /* calculate start of messages */ int r; @@ -89,10 +87,10 @@ PUBLIC void kmessages_dmp() * buffer into a print-buffer. This is done because the messages in the * copy may wrap (the kernel buffer is circular). */ - start = ((kmess.km_next + KMESS_BUF_SIZE) - kmess.km_size) % KMESS_BUF_SIZE; + start = ((kmess.km_next + _KMESS_BUF_SIZE) - kmess.km_size) % _KMESS_BUF_SIZE; r = 0; while (kmess.km_size > 0) { - print_buf[r] = kmess.km_buf[(start+r) % KMESS_BUF_SIZE]; + print_buf[r] = kmess.km_buf[(start+r) % _KMESS_BUF_SIZE]; r ++; kmess.km_size --; } @@ -283,14 +281,10 @@ PUBLIC void kenv_dmp() printf("- data_base: %5u\n", kinfo.data_base); printf("- data_size: %5u\n", kinfo.data_size); printf("- proc_addr: %5u\n", kinfo.proc_addr); - printf("- kmem_base: %5u\n", kinfo.kmem_base); - printf("- kmem_size: %5u\n", kinfo.kmem_size); printf("- bootdev_base: %5u\n", kinfo.bootdev_base); printf("- bootdev_size: %5u\n", kinfo.bootdev_size); printf("- ramdev_base: %5u\n", kinfo.ramdev_base); printf("- ramdev_size: %5u\n", kinfo.ramdev_size); - printf("- params_base: %5u\n", kinfo.params_base); - printf("- params_size: %5u\n", kinfo.params_size); printf("- nr_procs: %3u\n", kinfo.nr_procs); printf("- nr_tasks: %3u\n", kinfo.nr_tasks); printf("- release: %.6s\n", kinfo.release); @@ -351,7 +345,7 @@ PUBLIC void privileges_dmp() for (rp = oldrp; rp < END_PROC_ADDR; rp++) { if (isemptyp(rp)) continue; - if (++n > 23) break; + if (++n > LINES) break; if (proc_nr(rp) == IDLE) printf("(%2d) ", proc_nr(rp)); else if (proc_nr(rp) < 0) printf("[%2d] ", proc_nr(rp)); else printf(" %2d ", proc_nr(rp)); @@ -414,7 +408,7 @@ PUBLIC void sendmask_dmp() for (rp = oldrp; rp < END_PROC_ADDR; rp++) { if (isemptyp(rp)) continue; - if (++n > 20) break; + if (++n > LINES) break; printf("%8s ", rp->p_name); if (proc_nr(rp) == IDLE) printf("(%2d) ", proc_nr(rp)); @@ -467,11 +461,11 @@ PUBLIC void proctab_dmp() return; } - printf("\n-nr-----gen---endpoint-name--- -prior-quant- -user----sys----size-rts flags\n"); + printf("\n-nr-----gen---endpoint-name--- -prior-quant- -user----sys--rts flags\n"); for (rp = oldrp; rp < END_PROC_ADDR; rp++) { if (isemptyp(rp)) continue; - if (++n > 23) break; + if (++n > LINES) break; text = rp->p_memmap[T].mem_phys; data = rp->p_memmap[D].mem_phys; size = rp->p_memmap[T].mem_len @@ -480,12 +474,11 @@ PUBLIC void proctab_dmp() else if (proc_nr(rp) < 0) printf("[%2d] ", proc_nr(rp)); else printf(" %2d ", proc_nr(rp)); printf(" %5d %10d ", _ENDPOINT_G(rp->p_endpoint), rp->p_endpoint); - printf("%-8.8s %02u/%02u %02d/%02u %6lu %6lu %5uK %s", + printf("%-8.8s %02u/%02u %02d/%02u %6lu %6lu %s", rp->p_name, rp->p_priority, rp->p_max_priority, rp->p_ticks_left, rp->p_quantum_size, rp->p_user_time, rp->p_sys_time, - click_to_round_k(size), p_rts_flags_str(rp->p_rts_flags)); if (rp->p_rts_flags & (SENDING|RECEIVING)) { printf(" %-7.7s", proc_name(_ENDPOINT_P(rp->p_getfrom_e))); @@ -513,22 +506,22 @@ PUBLIC void memmap_dmp() return; } - printf("\n-nr/name--- --pc-- --sp-- -----text----- -----data----- ----stack----- --size-\n"); + printf("\n-nr/name--- --pc-- --sp-- -text---- -data---- -stack--- -cr3-\n"); for (rp = oldrp; rp < END_PROC_ADDR; rp++) { if (isemptyp(rp)) continue; - if (++n > 23) break; + if (++n > LINES) break; size = rp->p_memmap[T].mem_len + ((rp->p_memmap[S].mem_phys + rp->p_memmap[S].mem_len) - rp->p_memmap[D].mem_phys); - printf("%3d %-7.7s%7lx%7lx %4x %4x %4x %4x %4x %4x %4x %4x %4x %5uK\n", + printf("%3d %-7.7s%7lx %8lx %4x %4x %4x %4x %5x %5x %8lx\n", proc_nr(rp), rp->p_name, (unsigned long) rp->p_reg.pc, (unsigned long) rp->p_reg.sp, - rp->p_memmap[T].mem_vir, rp->p_memmap[T].mem_phys, rp->p_memmap[T].mem_len, - rp->p_memmap[D].mem_vir, rp->p_memmap[D].mem_phys, rp->p_memmap[D].mem_len, - rp->p_memmap[S].mem_vir, rp->p_memmap[S].mem_phys, rp->p_memmap[S].mem_len, - click_to_round_k(size)); + rp->p_memmap[T].mem_phys, rp->p_memmap[T].mem_len, + rp->p_memmap[D].mem_phys, rp->p_memmap[D].mem_len, + rp->p_memmap[S].mem_phys, rp->p_memmap[S].mem_len, + rp->p_seg.p_cr3); } if (rp == END_PROC_ADDR) rp = proc; else printf("--more--\r"); @@ -542,6 +535,11 @@ PRIVATE char *proc_name(proc_nr) int proc_nr; { if (proc_nr == ANY) return "ANY"; + /* + if(proc_nr < 0 || proc_nr >= NR_TASKS+NR_PROCS) { + return "BAD"; + } + */ return cproc_addr(proc_nr)->p_name; } diff --git a/servers/is/dmp_pm.c b/servers/is/dmp_pm.c index 2853aec2c..739d1162a 100644 --- a/servers/is/dmp_pm.c +++ b/servers/is/dmp_pm.c @@ -29,9 +29,6 @@ PRIVATE char *flags_str(int flags) str[5] = (flags & STOPPED) ? 'S' : '-'; str[6] = (flags & SIGSUSPENDED) ? 'U' : '-'; str[7] = (flags & REPLY) ? 'R' : '-'; - str[8] = (flags & ONSWAP) ? 'O' : '-'; - str[9] = (flags & SWAPIN) ? 'I' : '-'; - str[10] = (flags & DONT_SWAP) ? 'D' : '-'; str[11] = (flags & PRIV_PROC) ? 'P' : '-'; str[12] = '\0'; @@ -48,14 +45,14 @@ PUBLIC void mproc_dmp() getsysinfo(PM_PROC_NR, SI_PROC_TAB, mproc); - printf("-process- -nr-prnt- -pid/ppid/grp- -uid--gid- -nice- -flags------\n"); + printf("-process- -nr-prnt- -pid ppid grp- -uid--gid- -nice- -flags------\n"); for (i=prev_i; imp_pid == 0 && i != PM_PROC_NR) continue; if (++n > 22) break; - printf("%8.8s %4d%4d %4d%4d%4d ", + printf("%8.8s %4d%4d %5d %5d %5d ", mp->mp_name, i, mp->mp_parent, mp->mp_pid, mproc[mp->mp_parent].mp_pid, mp->mp_procgrp); - printf("%d(%d) %d(%d) ", + printf("%2d(%2d) %2d(%2d) ", mp->mp_realuid, mp->mp_effuid, mp->mp_realgid, mp->mp_effgid); printf(" %3d %s ", mp->mp_nice, flags_str(mp->mp_flags)); @@ -99,42 +96,4 @@ PUBLIC void sigaction_dmp() prev_i = i; } -/*===========================================================================* - * holes_dmp * - *===========================================================================*/ -PUBLIC void holes_dmp(void) -{ - static struct pm_mem_info pmi; - int h; - int largest_bytes = 0, total_bytes = 0; - - if(getsysinfo(PM_PROC_NR, SI_MEM_ALLOC, &pmi) != OK) { - printf("Obtaining memory hole list failed.\n"); - return; - } - printf("Available memory stats\n"); - - for(h = 0; h < _NR_HOLES; h++) { - if(pmi.pmi_holes[h].h_base && pmi.pmi_holes[h].h_len) { - int bytes; - bytes = (pmi.pmi_holes[h].h_len << CLICK_SHIFT); - printf("%08lx: %6d kB\n", - pmi.pmi_holes[h].h_base << CLICK_SHIFT, bytes / 1024); - if(bytes > largest_bytes) largest_bytes = bytes; - total_bytes += bytes; - } - } - printf("\n" - "Total memory free: %7d kB\n" - "Largest chunk: %7d kB\n" - "Uncontiguous rest: %7d kB (%d%% of total free)\n" - "Memory high watermark: %7d kB\n", - total_bytes/1024, - largest_bytes/1024, - (total_bytes-largest_bytes)/1024, - 100*(total_bytes/100-largest_bytes/100)/total_bytes, - (pmi.pmi_hi_watermark/1024 << CLICK_SHIFT)); - - return; -} diff --git a/servers/is/main.c b/servers/is/main.c index da01de270..db17cdaef 100644 --- a/servers/is/main.c +++ b/servers/is/main.c @@ -9,10 +9,6 @@ #include "inc.h" -/* Set debugging level to 0, 1, or 2 to see no, some, all debug output. */ -#define DEBUG_LEVEL 1 -#define DPRINTF if (DEBUG_LEVEL > 0) printf - /* Allocate space for the global variables. */ message m_in; /* the input message itself */ message m_out; /* the output message used for reply */ @@ -43,7 +39,6 @@ PUBLIC int main(int argc, char **argv) /* Main loop - get work and do it, forever. */ while (TRUE) { - /* Wait for incoming message, sets 'callnr' and 'who'. */ get_work(); diff --git a/servers/mfs/Makefile b/servers/mfs/Makefile index 1f97664ed..dc22f25d9 100644 --- a/servers/mfs/Makefile +++ b/servers/mfs/Makefile @@ -1,5 +1,8 @@ # Makefile for File System (FS) SERVER = mfs +DEST=/sbin/$(SERVER) +NR_BUFS=1024 +BS=4096 # directories u = /usr @@ -9,9 +12,9 @@ h = $i/minix # programs, flags, etc. CC = exec cc -CFLAGS = -I$i $(EXTRA_OPTS) $(CPROFILE) +CFLAGS = -I$i $(EXTRA_OPTS) $(CPROFILE) -DNR_BUFS=$(NR_BUFS) LDFLAGS = -i -LIBS = -lsysutil -lsys -ltimers +LIBS = -lsys -ltimers OBJ = cache.o device.o link.o \ mount.o misc.o open.o pipe.o protect.o read.o \ @@ -22,10 +25,11 @@ OBJ = cache.o device.o link.o \ all build: $(SERVER) $(SERVER): $(OBJ) $(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS) - install -S 64k $(SERVER) + install -S `expr $(NR_BUFS) \* $(BS) \* 2.2` $(SERVER) install: $(SERVER) - install $(SERVER) /sbin/$(SERVER) + -mv $(DEST) $(DEST).prev + install $(SERVER) $(DEST) # clean up local files clean: diff --git a/servers/mfs/buf.h b/servers/mfs/buf.h index a17513683..c703442aa 100644 --- a/servers/mfs/buf.h +++ b/servers/mfs/buf.h @@ -14,9 +14,7 @@ #include /* need struct direct */ #include -EXTERN struct buf { - /* Data portion of the buffer. */ - union { +union fsdata_u { char b__data[_MAX_BLOCK_SIZE]; /* ordinary user data */ /* directory block */ struct direct b__dir[NR_DIR_ENTRIES(_MAX_BLOCK_SIZE)]; @@ -30,32 +28,22 @@ EXTERN struct buf { d2_inode b__v2_ino[V2_INODES_PER_BLOCK(_MAX_BLOCK_SIZE)]; /* bit map block */ bitchunk_t b__bitmap[FS_BITMAP_CHUNKS(_MAX_BLOCK_SIZE)]; - } b; - - /* Header portion of the buffer. */ - struct buf *b_next; /* used to link all free bufs in a chain */ - struct buf *b_prev; /* used to link all free bufs the other way */ - struct buf *b_hash; /* used to link bufs on hash chains */ - block_t b_blocknr; /* block number of its (minor) device */ - dev_t b_dev; /* major | minor device where block resides */ - char b_dirt; /* CLEAN or DIRTY */ - char b_count; /* number of users of this buffer */ -} buf[NR_BUFS]; +}; /* A block is free if b_dev == NO_DEV. */ #define NIL_BUF ((struct buf *) 0) /* indicates absence of a buffer */ /* These defs make it possible to use to bp->b_data instead of bp->b.b__data */ -#define b_data b.b__data -#define b_dir b.b__dir -#define b_v1_ind b.b__v1_ind -#define b_v2_ind b.b__v2_ind -#define b_v1_ino b.b__v1_ino -#define b_v2_ino b.b__v2_ino -#define b_bitmap b.b__bitmap +#define b_data bp->b__data +#define b_dir bp->b__dir +#define b_v1_ind bp->b__v1_ind +#define b_v2_ind bp->b__v2_ind +#define b_v1_ino bp->b__v1_ino +#define b_v2_ino bp->b__v2_ino +#define b_bitmap bp->b__bitmap -EXTERN struct buf *buf_hash[NR_BUF_HASH]; /* the buffer hash table */ +#define BUFHASH(b) ((b) % NR_BUFS) EXTERN struct buf *front; /* points to least recently used free block */ EXTERN struct buf *rear; /* points to most recently used free block */ @@ -72,4 +60,3 @@ EXTERN int bufs_in_use; /* # bufs currently in use (not on free list)*/ #define FULL_DATA_BLOCK 5 /* data, fully used */ #define PARTIAL_DATA_BLOCK 6 /* data, partly used*/ -#define HASH_MASK (NR_BUF_HASH - 1) /* mask for hashing block numbers */ diff --git a/servers/mfs/cache.c b/servers/mfs/cache.c index 352295387..ed04fc364 100644 --- a/servers/mfs/cache.c +++ b/servers/mfs/cache.c @@ -19,12 +19,11 @@ #include #include "buf.h" #include "super.h" +#include "inode.h" FORWARD _PROTOTYPE( void rm_lru, (struct buf *bp) ); FORWARD _PROTOTYPE( int rw_block, (struct buf *, int) ); -#define ENABLE_CACHE2 0 - /*===========================================================================* * get_block * *===========================================================================*/ @@ -51,20 +50,24 @@ int only_search; /* if NO_READ, don't read, else act normal */ int b; register struct buf *bp, *prev_ptr; + ASSERT(fs_block_size > 0); + /* Search the hash chain for (dev, block). Do_read() can use * get_block(NO_DEV ...) to get an unnamed block to fill with zeros when * someone wants to read from a hole in a file, in which case this search * is skipped */ if (dev != NO_DEV) { - b = (int) block & HASH_MASK; + b = BUFHASH(block); bp = buf_hash[b]; while (bp != NIL_BUF) { if (bp->b_blocknr == block && bp->b_dev == dev) { /* Block needed has been found. */ if (bp->b_count == 0) rm_lru(bp); bp->b_count++; /* record that block is in use */ - + ASSERT(bp->b_dev == dev); + ASSERT(bp->b_dev != NO_DEV); + ASSERT(bp->bp); return(bp); } else { /* This block is not the one sought. */ @@ -78,7 +81,7 @@ int only_search; /* if NO_READ, don't read, else act normal */ rm_lru(bp); /* Remove the block that was just taken from its hash chain. */ - b = (int) bp->b_blocknr & HASH_MASK; + b = BUFHASH(bp->b_blocknr); prev_ptr = buf_hash[b]; if (prev_ptr == bp) { buf_hash[b] = bp->b_hash; @@ -98,31 +101,42 @@ int only_search; /* if NO_READ, don't read, else act normal */ */ if (bp->b_dev != NO_DEV) { if (bp->b_dirt == DIRTY) flushall(bp->b_dev); -#if ENABLE_CACHE2 - put_block2(bp); -#endif } /* Fill in block's parameters and add it to the hash chain where it goes. */ bp->b_dev = dev; /* fill in device number */ bp->b_blocknr = block; /* fill in block number */ bp->b_count++; /* record that block is being used */ - b = (int) bp->b_blocknr & HASH_MASK; + b = BUFHASH(bp->b_blocknr); bp->b_hash = buf_hash[b]; + if(bp->b_bytes < fs_block_size) { + static int n = 0; + phys_bytes ph; + if(bp->b_bytes > 0) + printf("MFS: WARNING: throwing away %d bytes!\n", + bp->b_bytes); + if(!(bp->bp = alloc_contig(fs_block_size, 0, &ph))) + panic(__FILE__,"couldn't allocate FS buffer", n); + bp->b_bytes = fs_block_size; + n++; + } + buf_hash[b] = bp; /* add to hash list */ + SANITYCHECK; + /* Go get the requested block unless searching or prefetching. */ if (dev != NO_DEV) { -#if ENABLE_CACHE2 - if (get_block2(bp, only_search)) /* in 2nd level cache */; - else -#endif if (only_search == PREFETCH) bp->b_dev = NO_DEV; else if (only_search == NORMAL) { + SANITYCHECK; rw_block(bp, READING); } } + + ASSERT(bp->bp); + return(bp); /* return the newly acquired block */ } @@ -262,15 +276,14 @@ int rw_flag; /* READING or WRITING */ int r, op; u64_t pos; dev_t dev; - int block_size; - - block_size = get_block_size(bp->b_dev); if ( (dev = bp->b_dev) != NO_DEV) { - pos = mul64u(bp->b_blocknr, block_size); + pos = mul64u(bp->b_blocknr, fs_block_size); op = (rw_flag == READING ? MFS_DEV_READ : MFS_DEV_WRITE); - r = block_dev_io(op, dev, SELF_E, bp->b_data, pos, block_size, 0); - if (r != block_size) { + SANITYCHECK; + r = block_dev_io(op, dev, SELF_E, bp->b_data, pos, fs_block_size, 0); + SANITYCHECK; + if (r != fs_block_size) { if (r >= 0) r = END_OF_FILE; if (r != END_OF_FILE) printf("MFS(%d) I/O error on device %d/%d, block %ld\n", @@ -282,6 +295,14 @@ int rw_flag; /* READING or WRITING */ /* Report read errors to interested parties. */ if (rw_flag == READING) rdwt_err = r; } + if(op == MFS_DEV_READ) { + int i; +#if 0 + printf("mfsread after contents: 0x%lx, ", bp->b_data); + for(i = 0; i < 10; i++) printf("%02lx ", (unsigned char) bp->b_data[i]); + printf("\n"); +#endif + } } bp->b_dirt = CLEAN; @@ -301,10 +322,6 @@ dev_t device; /* device whose blocks are to be purged */ for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) if (bp->b_dev == device) bp->b_dev = NO_DEV; - -#if ENABLE_CACHE2 - invalidate2(device); -#endif } /*===========================================================================* @@ -316,9 +333,11 @@ dev_t dev; /* device to flush */ /* Flush all dirty blocks for one device. */ register struct buf *bp; - static struct buf *dirty[NR_BUFS]; /* static so it isn't on stack */ + static struct buf **dirty; /* static so it isn't on stack */ int ndirty; + STATICINIT(dirty, NR_BUFS); + for (bp = &buf[0], ndirty = 0; bp < &buf[NR_BUFS]; bp++) if (bp->b_dirt == DIRTY && bp->b_dev == dev) dirty[ndirty++] = bp; rw_scattered(dev, dirty, ndirty, WRITING); @@ -339,11 +358,10 @@ int rw_flag; /* READING or WRITING */ int gap; register int i; register iovec_t *iop; - static iovec_t iovec[NR_IOREQS]; /* static so it isn't on stack */ + static iovec_t *iovec = NULL; int j, r; - int block_size; - block_size = get_block_size(dev); + STATICINIT(iovec, NR_IOREQS); /* (Shell) sort buffers on b_blocknr. */ gap = 1; @@ -371,11 +389,11 @@ int rw_flag; /* READING or WRITING */ bp = bufq[j]; if (bp->b_blocknr != bufq[0]->b_blocknr + j) break; iop->iov_addr = (vir_bytes) bp->b_data; - iop->iov_size = block_size; + iop->iov_size = fs_block_size; } r = block_dev_io(rw_flag == WRITING ? MFS_DEV_SCATTER : MFS_DEV_GATHER, dev, SELF_E, iovec, - mul64u(bufq[0]->b_blocknr, block_size), j, 0); + mul64u(bufq[0]->b_blocknr, fs_block_size), j, 0); /* Harvest the results. Dev_io reports the first error it may have * encountered, but we only care if it's the first block that failed. @@ -444,3 +462,58 @@ struct buf *bp; else rear = prev_ptr; /* this block was at rear of chain */ } + +/*===========================================================================* + * set_blocksize * + *===========================================================================*/ +PUBLIC void set_blocksize(int blocksize) +{ + struct buf *bp; + struct inode *rip; + + ASSERT(blocksize > 0); + + for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) + if(bp->b_count != 0) + panic("MFS", "change blocksize with buffer in use", + NO_NUM); + + for (rip = &inode[0]; rip < &inode[NR_INODES]; rip++) + if (rip->i_count > 0) + panic("MFS", "change blocksize with inode in use", + NO_NUM); + + fs_sync(); + + buf_pool(); + fs_block_size = blocksize; +} + +/*===========================================================================* + * buf_pool * + *===========================================================================*/ +PUBLIC void buf_pool(void) +{ +/* Initialize the buffer pool. */ + register struct buf *bp; + + 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; + bp->bp = NULL; + bp->b_bytes = 0; + } + buf[0].b_prev = NIL_BUF; + buf[NR_BUFS - 1].b_next = NIL_BUF; + + for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) bp->b_hash = bp->b_next; + buf_hash[0] = front; + +} + diff --git a/servers/mfs/const.h b/servers/mfs/const.h index c592d9d63..e3584908b 100644 --- a/servers/mfs/const.h +++ b/servers/mfs/const.h @@ -5,7 +5,6 @@ #define V2_NR_TZONES 10 /* total # zone numbers in a V2 inode */ #define NR_INODES 256 /* # slots in "in core" inode table */ -#define NR_SUPERS 1 /* # slots in super block table */ #define INODE_HASH_LOG2 7 /* 2 based logarithm of the inode hash size */ #define INODE_HASH_SIZE ((unsigned long)1<> MAJOR) & BYTE].driver_e; diff --git a/servers/mfs/glo.h b/servers/mfs/glo.h index e5595a852..bde97a4e3 100644 --- a/servers/mfs/glo.h +++ b/servers/mfs/glo.h @@ -45,3 +45,10 @@ EXTERN char fs_dev_label[16]; /* Name of the device driver that is handled * by this FS proc. */ +/* our block size. */ +EXTERN int fs_block_size; + +/* Buffer cache. */ +EXTERN struct buf buf[NR_BUFS]; +EXTERN struct buf *buf_hash[NR_BUFS]; /* the buffer hash table */ + diff --git a/servers/mfs/main.c b/servers/mfs/main.c index 32f7cc41b..6118748e6 100644 --- a/servers/mfs/main.c +++ b/servers/mfs/main.c @@ -117,33 +117,6 @@ PUBLIC int main(void) } } -/*===========================================================================* - * buf_pool * - *===========================================================================*/ -PRIVATE void buf_pool(void) -{ -/* Initialize the buffer pool. */ - register struct buf *bp; - - 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; - - for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) bp->b_hash = bp->b_next; - buf_hash[0] = front; - -} - - /*===========================================================================* * init_server * *===========================================================================*/ @@ -165,6 +138,7 @@ PRIVATE void init_server(void) SELF_E = getprocnr(); buf_pool(); + fs_block_size = _MIN_BLOCK_SIZE; } /*===========================================================================* diff --git a/servers/mfs/mount.c b/servers/mfs/mount.c index 2a802b925..f3a11b9ba 100644 --- a/servers/mfs/mount.c +++ b/servers/mfs/mount.c @@ -25,7 +25,7 @@ PUBLIC int fs_readsuper_s() * so that the VFS knows that it has to find the vnode on which this FS * process' partition is mounted on. */ - struct super_block *xp, *sp; + struct super_block *xp; struct inode *root_ip; cp_grant_id_t label_gid; size_t label_len; @@ -60,11 +60,6 @@ PUBLIC int fs_readsuper_s() return EINVAL; } -#if 0 - printf("mfs:fs_readsuper: got tasknr %d for label '%s'\n", - tasknr, fs_dev_label); -#endif - driver_e= tasknr; /* Map the driver endpoint for this major */ @@ -76,8 +71,6 @@ PUBLIC int fs_readsuper_s() * with old lookup code. */; - sp = &super_block[0]; - /* Open the device the file system lives on. */ if (dev_open(driver_e, fs_dev, driver_e, fs_m_in.REQ_READONLY ? R_BIT : (R_BIT|W_BIT)) != OK) { @@ -85,32 +78,37 @@ PUBLIC int fs_readsuper_s() } /* Fill in the super block. */ - sp->s_dev = fs_dev; /* read_super() needs to know which dev */ - r = read_super(sp); + superblock.s_dev = fs_dev; /* read_super() needs to know which dev */ + r = read_super(&superblock); /* Is it recognized as a Minix filesystem? */ if (r != OK) { - sp->s_dev = NO_DEV; + printf("MFS: bad superblock\n"); + superblock.s_dev = NO_DEV; dev_close(driver_e, fs_dev); return(r); } + + set_blocksize(superblock.s_block_size); /* Get the root inode of the mounted file system. */ if ( (root_ip = get_inode(fs_dev, ROOT_INODE)) == NIL_INODE) { - sp->s_dev = NO_DEV; + printf("MFS: couldn't get root inode?!\n"); + superblock.s_dev = NO_DEV; dev_close(driver_e, fs_dev); - return err_code; + return EINVAL; } if (root_ip != NIL_INODE && root_ip->i_mode == 0) { + printf("MFS: zero mode for root inode?!\n"); put_inode(root_ip); - sp->s_dev = NO_DEV; + superblock.s_dev = NO_DEV; dev_close(driver_e, fs_dev); return EINVAL; } - sp->s_rd_only = fs_m_in.REQ_READONLY; - sp->s_is_root = fs_m_in.REQ_ISROOT; + superblock.s_rd_only = fs_m_in.REQ_READONLY; + superblock.s_is_root = fs_m_in.REQ_ISROOT; /* Root inode properties */ fs_m_out.RES_INODE_NR = root_ip->i_num; @@ -135,9 +133,10 @@ PUBLIC int fs_readsuper_o() * so that the VFS knows that it has to find the vnode on which this FS * process' partition is mounted on. */ - struct super_block *xp, *sp; + struct super_block *xp; struct inode *root_ip; int r = OK; + phys_bytes ph; fs_dev = fs_m_in.REQ_DEV; @@ -146,17 +145,17 @@ PUBLIC int fs_readsuper_o() boottime = fs_m_in.REQ_BOOTTIME; vfs_slink_storage = fs_m_in.REQ_SLINK_STORAGE; - sp = &super_block[0]; - /* Fill in the super block. */ - sp->s_dev = fs_dev; /* read_super() needs to know which dev */ - r = read_super(sp); + superblock.s_dev = fs_dev; /* read_super() needs to know which dev */ + r = read_super(&superblock); /* Is it recognized as a Minix filesystem? */ if (r != OK) { - sp->s_dev = NO_DEV; + superblock.s_dev = NO_DEV; return(r); } + + set_blocksize(superblock.s_block_size); /* Get the root inode of the mounted file system. */ root_ip = NIL_INODE; /* if 'r' not OK, make sure this is defined */ @@ -171,8 +170,8 @@ PUBLIC int fs_readsuper_o() } if (r != OK) return r; - sp->s_rd_only = fs_m_in.REQ_READONLY; - sp->s_is_root = fs_m_in.REQ_ISROOT; + superblock.s_rd_only = fs_m_in.REQ_READONLY; + superblock.s_is_root = fs_m_in.REQ_ISROOT; /* Root inode properties */ fs_m_out.RES_INODE_NR = root_ip->i_num; @@ -180,8 +179,8 @@ PUBLIC int fs_readsuper_o() fs_m_out.RES_FILE_SIZE = root_ip->i_size; /* Partition properties */ - fs_m_out.RES_MAXSIZE = sp->s_max_size; - fs_m_out.RES_BLOCKSIZE = sp->s_block_size; + fs_m_out.RES_MAXSIZE = superblock.s_max_size; + fs_m_out.RES_BLOCKSIZE = superblock.s_block_size; return r; } @@ -280,26 +279,15 @@ printf("MFS(%d) get_inode by fs_mountpoint() failed\n", SELF_E); PUBLIC int fs_unmount() { /* Unmount a file system by device number. */ - struct super_block *sp, *sp1; + struct super_block *sp1; int count; register struct inode *rip; /* Close the device the file system lives on. */ dev_close(driver_endpoints[(fs_dev >> MAJOR) & BYTE].driver_e, fs_dev); - /* !!!!!!!!!!!!! REMOVE THIS LATER !!!!!!!!!!!!!!!!!!!!!!! */ - /* Find the super block. */ - sp = NIL_SUPER; - for (sp1 = &super_block[0]; sp1 < &super_block[NR_SUPERS]; sp1++) { - if (sp1->s_dev == fs_dev) { - sp = sp1; - break; - } - } - if (sp == NIL_SUPER) { - return(EINVAL); - } - /* !!!!!!!!!!!!! REMOVE THIS LATER !!!!!!!!!!!!!!!!!!!!!!! */ + if(superblock.s_dev != fs_dev) + return EINVAL; /* See if the mounted device is busy. Only 1 inode using it should be * open -- the root inode -- and that inode only 1 time. @@ -314,7 +302,6 @@ PUBLIC int fs_unmount() } if (count > 1) { - printf("MFS(%d) unmount: filesystem is busy %d\n", SELF_E, count); return(EBUSY); /* can't umount a busy file system */ } @@ -325,10 +312,9 @@ PUBLIC int fs_unmount() /* Sync the disk, and invalidate cache. */ (void) fs_sync(); /* force any cached blocks out of memory */ - /*invalidate(fs_dev);*/ /* invalidate cache entries for this dev */ /* Finish off the unmount. */ - sp->s_dev = NO_DEV; + superblock.s_dev = NO_DEV; return OK; diff --git a/servers/mfs/proto.h b/servers/mfs/proto.h index cea152dd3..3e85a0225 100644 --- a/servers/mfs/proto.h +++ b/servers/mfs/proto.h @@ -39,16 +39,10 @@ _PROTOTYPE( void free_zone, (Dev_t dev, zone_t numb) ); _PROTOTYPE( struct buf *get_block, (Dev_t dev, block_t block,int only_search)); _PROTOTYPE( void invalidate, (Dev_t device) ); _PROTOTYPE( void put_block, (struct buf *bp, int block_type) ); +_PROTOTYPE( void set_blocksize, (int blocksize) ); _PROTOTYPE( void rw_scattered, (Dev_t dev, struct buf **bufq, int bufqsize, int rw_flag) ); - -#if ENABLE_CACHE2 -/* cache2.c */ -_PROTOTYPE( void init_cache2, (unsigned long size) ); -_PROTOTYPE( int get_block2, (struct buf *bp, int only_search) ); -_PROTOTYPE( void put_block2, (struct buf *bp) ); -_PROTOTYPE( void invalidate2, (Dev_t device) ); -#endif +_PROTOTYPE( void buf_pool, (void) ); /* device.c */ _PROTOTYPE( int block_dev_io, (int op, Dev_t dev, int proc, void *buf, @@ -200,9 +194,11 @@ _PROTOTYPE( long conv4, (int norm, long x) ); _PROTOTYPE( int fetch_name, (char *path, int len, int flag) ); _PROTOTYPE( int no_sys, (void) ); _PROTOTYPE( int isokendpt_f, (char *f, int l, int e, int *p, int ft)); -_PROTOTYPE( void panic, (char *who, char *mess, int num) ); _PROTOTYPE( void mfs_nul_f, (char *file, int line, char *str, int len, int maxlen)); _PROTOTYPE( int mfs_min_f, (char *file, int line, int len1, int len2) ); +_PROTOTYPE( void sanitycheck, (char *file, int line) ); + +#define SANITYCHECK sanitycheck(__FILE__, __LINE__) #define okendpt(e, p) isokendpt_f(__FILE__, __LINE__, (e), (p), 1) #define isokendpt(e, p) isokendpt_f(__FILE__, __LINE__, (e), (p), 0) diff --git a/servers/mfs/read.c b/servers/mfs/read.c index 6c789bdc8..063461dbb 100644 --- a/servers/mfs/read.c +++ b/servers/mfs/read.c @@ -675,8 +675,11 @@ off_t position; /* position in file whose blk wanted */ if ( (z = rip->i_zone[dzones+1]) == NO_ZONE) return(NO_BLOCK); excess -= nr_indirects; /* single indir doesn't count*/ b = (block_t) z << scale; + ASSERT(rip->i_dev != NO_DEV); bp = get_block(rip->i_dev, b, NORMAL); /* get double indirect block */ index = (int) (excess/nr_indirects); + ASSERT(bp->b_dev != NO_DEV); + ASSERT(bp->b_dev == rip->i_dev); z = rd_indir(bp, index); /* z= zone for single*/ put_block(bp, INDIRECT_BLOCK); /* release double ind block */ excess = excess % nr_indirects; /* index into single ind blk */ @@ -773,7 +776,9 @@ unsigned bytes_ahead; /* bytes beyond position for immediate use */ off_t ind1_pos; dev_t dev; struct buf *bp; - static struct buf *read_q[NR_BUFS]; + static struct buf **read_q; + + STATICINIT(read_q, NR_BUFS); block_spec = (rip->i_mode & I_TYPE) == I_BLOCK_SPECIAL; if (block_spec) { diff --git a/servers/mfs/super.c b/servers/mfs/super.c index 466ff98ad..4715b6c7c 100644 --- a/servers/mfs/super.c +++ b/servers/mfs/super.c @@ -148,21 +148,13 @@ bit_t bit_returned; /* number of bit to insert into the map */ PUBLIC struct super_block *get_super(dev) dev_t dev; /* device number whose super_block is sought */ { -/* Search the superblock table for this device. It is supposed to be there. */ - - register struct super_block *sp; - if (dev == NO_DEV) panic(__FILE__,"request for super_block of NO_DEV", NO_NUM); - for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++) - if (sp->s_dev == dev) return(sp); -printf("MFS(%d)get_super: sp->s_dev: %d, dev: %d\n", SELF_E, sp->s_dev, dev); + if(superblock.s_dev != dev) + panic(__FILE__,"wrong superblock", (int) dev); - /* Search failed. Something wrong. */ - panic(__FILE__,"can't find superblock for device (in decimal)", (int) dev); - - return(NIL_SUPER); /* to keep the compiler and lint quiet */ + return &superblock; } /*===========================================================================* @@ -170,21 +162,24 @@ printf("MFS(%d)get_super: sp->s_dev: %d, dev: %d\n", SELF_E, sp->s_dev, dev); *===========================================================================*/ PUBLIC int get_block_size(dev_t dev) { -/* Search the superblock table for this device. */ - - register struct super_block *sp; - if (dev == NO_DEV) panic(__FILE__,"request for block size of NO_DEV", NO_NUM); - for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++) { - if (sp->s_dev == dev) { - return(sp->s_block_size); + return fs_block_size; + +#if 0 + if(superblock.s_dev == dev) { + if(superblock.s_block_size != fs_block_size) { + printf("mounted blocksize: %d my blocksize: %d\n", + superblock.s_block_size, fs_block_size); } + ASSERT(superblock.s_block_size == fs_block_size); + return(superblock.s_block_size); } - /* no mounted filesystem? use this block size then. */ + /* not the mounted filesystem? use this block size then. */ return _MIN_BLOCK_SIZE; +#endif } /*===========================================================================* @@ -196,14 +191,13 @@ PUBLIC int mounted(rip) register struct inode *rip; { - register struct super_block *sp; register dev_t dev; dev = (dev_t) rip->i_zone[0]; if (dev == root_dev) return(TRUE); - for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++) - if (sp->s_dev == dev) return(TRUE); + if(superblock.s_dev == dev) + return TRUE; return(FALSE); } @@ -218,7 +212,9 @@ register struct super_block *sp; /* pointer to a superblock */ dev_t dev; int magic; int version, native, r; - static char sbbuf[_MIN_BLOCK_SIZE]; + static char *sbbuf; + + STATICINIT(sbbuf, _MIN_BLOCK_SIZE); dev = sp->s_dev; /* save device (will be overwritten by copy) */ if (dev == NO_DEV) diff --git a/servers/mfs/super.h b/servers/mfs/super.h index c9e4761a2..f86db36ad 100644 --- a/servers/mfs/super.h +++ b/servers/mfs/super.h @@ -54,7 +54,7 @@ EXTERN struct super_block { bit_t s_isearch; /* inodes below this bit number are in use */ bit_t s_zsearch; /* all zones below this bit number are in use*/ char s_is_root; -} super_block[NR_SUPERS]; +} superblock; #define NIL_SUPER (struct super_block *) 0 #define IMAP 0 /* operating on the inode bit map */ diff --git a/servers/mfs/type.h b/servers/mfs/type.h index 19749fef0..63576838d 100644 --- a/servers/mfs/type.h +++ b/servers/mfs/type.h @@ -21,3 +21,19 @@ typedef struct { /* V2.x disk inode */ time_t d2_ctime; /* when was inode data last changed */ zone_t d2_zone[V2_NR_TZONES]; /* block nums for direct, ind, and dbl ind */ } d2_inode; + +struct buf { + /* Data portion of the buffer. */ + union fsdata_u *bp; + + /* Header portion of the buffer. */ + struct buf *b_next; /* used to link all free bufs in a chain */ + struct buf *b_prev; /* used to link all free bufs the other way */ + struct buf *b_hash; /* used to link bufs on hash chains */ + block_t b_blocknr; /* block number of its (minor) device */ + dev_t b_dev; /* major | minor device where block resides */ + char b_dirt; /* CLEAN or DIRTY */ + char b_count; /* number of users of this buffer */ + int b_bytes; /* Number of bytes allocated in bp */ +}; + diff --git a/servers/mfs/utility.c b/servers/mfs/utility.c index f4af5cfd8..24ca6bac1 100644 --- a/servers/mfs/utility.c +++ b/servers/mfs/utility.c @@ -12,8 +12,6 @@ #include -static int panicking; - /*===========================================================================* * no_sys * *===========================================================================*/ @@ -24,29 +22,6 @@ PUBLIC int no_sys() return(EINVAL); } -/*===========================================================================* - * panic * - *===========================================================================*/ -PUBLIC void panic(who, mess, num) -char *who; /* who caused the panic */ -char *mess; /* panic message string */ -int num; /* number to go with it */ -{ -/* Something awful has happened. Panics are caused when an internal - * inconsistency is detected, e.g., a programming error or illegal value of a - * defined constant. - */ - if (!panicking) { /* do not panic during a sync */ - panicking = TRUE; /* prevent another panic during the sync */ - - printf("MFS panic (%s): %s ", who, mess); - if (num != NO_NUM) printf("%d",num); - printf("\n"); - (void) fs_sync(); /* flush everything to the disk */ - } else printf("MFS re-panic\n"); - exit(1); -} - /*===========================================================================* * conv2 * *===========================================================================*/ @@ -100,7 +75,7 @@ PUBLIC time_t clock_time() if ( (k=getuptime(&uptime)) != OK) panic(__FILE__,"clock_time err", k); } - return( (time_t) (boottime + (uptime/HZ))); + return( (time_t) (boottime + (uptime/sys_hz()))); } int mfs_min_f(char *file, int line, int v1, int v2) @@ -130,3 +105,18 @@ void mfs_nul_f(char *file, int line, char *str, int len, int maxlen) file, line, len, maxlen); } } + +#define MYASSERT(c) if(!(c)) { printf("MFS:%s:%d: sanity check: %s failed\n", \ + file, line, #c); panic("MFS", "sanity check " #c " failed", __LINE__); } + +void sanitycheck(char *file, int line) +{ + MYASSERT(SELF_E > 0); + if(superblock.s_dev != NO_DEV) { + MYASSERT(superblock.s_dev == fs_dev); + MYASSERT(superblock.s_block_size == fs_block_size); + } else { + MYASSERT(_MIN_BLOCK_SIZE == fs_block_size); + } +} + diff --git a/servers/mfs/write.c b/servers/mfs/write.c index 638dc2c9c..73b2b923e 100644 --- a/servers/mfs/write.c +++ b/servers/mfs/write.c @@ -330,7 +330,9 @@ PUBLIC void zero_block(bp) register struct buf *bp; /* pointer to buffer to zero */ { /* Zero a block. */ - memset(bp->b_data, 0, _MAX_BLOCK_SIZE); + ASSERT(bp->b_bytes > 0); + ASSERT(bp->bp); + memset(bp->b_data, 0, bp->b_bytes); bp->b_dirt = DIRTY; } diff --git a/servers/pm/Makefile b/servers/pm/Makefile index 8ae60194f..d82db2cff 100644 --- a/servers/pm/Makefile +++ b/servers/pm/Makefile @@ -17,14 +17,14 @@ CFLAGS = $(CPROFILE) $(CPPFLAGS) LDFLAGS = -i OBJ = main.o forkexit.o break.o exec.o time.o timers.o \ - signal.o alloc.o utility.o table.o trace.o getset.o misc.o \ - profile.o asynsend.o kputc.o + signal.o utility.o table.o trace.o getset.o misc.o \ + profile.o kputc.o dma.o # build local binary all build: $(SERVER) $(SERVER): $(OBJ) - $(CC) -o $@ $(LDFLAGS) $(OBJ) -lsysutil -lsys -ltimers - install -S 8k $@ + $(CC) -o $@ $(LDFLAGS) $(OBJ) -lsys -ltimers + install -S 32k $@ # install with other servers install: /usr/sbin/$(SERVER) diff --git a/servers/pm/alloc.c b/servers/pm/alloc.c deleted file mode 100644 index d36c963f3..000000000 --- a/servers/pm/alloc.c +++ /dev/null @@ -1,655 +0,0 @@ -/* This file is concerned with allocating and freeing arbitrary-size blocks of - * physical memory on behalf of the FORK and EXEC system calls. The key data - * structure used is the hole table, which maintains a list of holes in memory. - * It is kept sorted in order of increasing memory address. The addresses - * it contains refers to physical memory, starting at absolute address 0 - * (i.e., they are not relative to the start of PM). During system - * initialization, that part of memory containing the interrupt vectors, - * kernel, and PM are "allocated" to mark them as not available and to - * remove them from the hole list. - * - * The entry points into this file are: - * alloc_mem: allocate a given sized chunk of memory - * free_mem: release a previously allocated chunk of memory - * mem_init: initialize the tables when PM start up - * max_hole: returns the largest hole currently available - * mem_holes_copy: for outsiders who want a copy of the hole-list - */ - -#include "pm.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include "mproc.h" -#include "../../kernel/const.h" -#include "../../kernel/config.h" -#include "../../kernel/type.h" - -#define NIL_HOLE (struct hole *) 0 - -PRIVATE struct hole hole[_NR_HOLES]; -PRIVATE u32_t high_watermark = 0; - -PRIVATE struct hole *hole_head; /* pointer to first hole */ -PRIVATE struct hole *free_slots;/* ptr to list of unused table slots */ -#if ENABLE_SWAP -PRIVATE int swap_fd = -1; /* file descriptor of open swap file/device */ -PRIVATE u32_t swap_offset; /* offset to start of swap area on swap file */ -PRIVATE phys_clicks swap_base; /* memory offset chosen as swap base */ -PRIVATE phys_clicks swap_maxsize;/* maximum amount of swap "memory" possible */ -PRIVATE struct mproc *in_queue; /* queue of processes wanting to swap in */ -PRIVATE struct mproc *outswap = &mproc[0]; /* outswap candidate? */ -#else /* ! ENABLE_SWAP */ -#define swap_base ((phys_clicks) -1) -#endif /* ENABLE_SWAP */ - -FORWARD _PROTOTYPE( void del_slot, (struct hole *prev_ptr, struct hole *hp) ); -FORWARD _PROTOTYPE( void merge, (struct hole *hp) ); -#if ENABLE_SWAP -FORWARD _PROTOTYPE( int swap_out, (void) ); -#else -#define swap_out() (0) -#endif - -/*===========================================================================* - * alloc_mem * - *===========================================================================*/ -PUBLIC phys_clicks alloc_mem(clicks) -phys_clicks clicks; /* amount of memory requested */ -{ -/* Allocate a block of memory from the free list using first fit. The block - * consists of a sequence of contiguous bytes, whose length in clicks is - * given by 'clicks'. A pointer to the block is returned. The block is - * always on a click boundary. This procedure is called when memory is - * needed for FORK or EXEC. Swap other processes out if needed. - */ - register struct hole *hp, *prev_ptr; - phys_clicks old_base; - - do { - prev_ptr = NIL_HOLE; - hp = hole_head; - while (hp != NIL_HOLE && hp->h_base < swap_base) { - if (hp->h_len >= clicks) { - /* We found a hole that is big enough. Use it. */ - old_base = hp->h_base; /* remember where it started */ - hp->h_base += clicks; /* bite a piece off */ - hp->h_len -= clicks; /* ditto */ - - /* Remember new high watermark of used memory. */ - if(hp->h_base > high_watermark) - high_watermark = hp->h_base; - - /* Delete the hole if used up completely. */ - if (hp->h_len == 0) del_slot(prev_ptr, hp); - - /* Return the start address of the acquired block. */ - return(old_base); - } - - prev_ptr = hp; - hp = hp->h_next; - } - } while (swap_out()); /* try to swap some other process out */ - return(NO_MEM); -} - -/*===========================================================================* - * free_mem * - *===========================================================================*/ -PUBLIC void free_mem(base, clicks) -phys_clicks base; /* base address of block to free */ -phys_clicks clicks; /* number of clicks to free */ -{ -/* Return a block of free memory to the hole list. The parameters tell where - * the block starts in physical memory and how big it is. The block is added - * to the hole list. If it is contiguous with an existing hole on either end, - * it is merged with the hole or holes. - */ - register struct hole *hp, *new_ptr, *prev_ptr; - - if (clicks == 0) return; - if ( (new_ptr = free_slots) == NIL_HOLE) - panic(__FILE__,"hole table full", NO_NUM); - new_ptr->h_base = base; - new_ptr->h_len = clicks; - free_slots = new_ptr->h_next; - hp = hole_head; - - /* If this block's address is numerically less than the lowest hole currently - * available, or if no holes are currently available, put this hole on the - * front of the hole list. - */ - if (hp == NIL_HOLE || base <= hp->h_base) { - /* Block to be freed goes on front of the hole list. */ - new_ptr->h_next = hp; - hole_head = new_ptr; - merge(new_ptr); - return; - } - - /* Block to be returned does not go on front of hole list. */ - prev_ptr = NIL_HOLE; - while (hp != NIL_HOLE && base > hp->h_base) { - prev_ptr = hp; - hp = hp->h_next; - } - - /* We found where it goes. Insert block after 'prev_ptr'. */ - new_ptr->h_next = prev_ptr->h_next; - prev_ptr->h_next = new_ptr; - merge(prev_ptr); /* sequence is 'prev_ptr', 'new_ptr', 'hp' */ -} - -/*===========================================================================* - * del_slot * - *===========================================================================*/ -PRIVATE void del_slot(prev_ptr, hp) -/* pointer to hole entry just ahead of 'hp' */ -register struct hole *prev_ptr; -/* pointer to hole entry to be removed */ -register struct hole *hp; -{ -/* Remove an entry from the hole list. This procedure is called when a - * request to allocate memory removes a hole in its entirety, thus reducing - * the numbers of holes in memory, and requiring the elimination of one - * entry in the hole list. - */ - if (hp == hole_head) - hole_head = hp->h_next; - else - prev_ptr->h_next = hp->h_next; - - hp->h_next = free_slots; - hp->h_base = hp->h_len = 0; - free_slots = hp; -} - -/*===========================================================================* - * merge * - *===========================================================================*/ -PRIVATE void merge(hp) -register struct hole *hp; /* ptr to hole to merge with its successors */ -{ -/* Check for contiguous holes and merge any found. Contiguous holes can occur - * when a block of memory is freed, and it happens to abut another hole on - * either or both ends. The pointer 'hp' points to the first of a series of - * three holes that can potentially all be merged together. - */ - register struct hole *next_ptr; - - /* If 'hp' points to the last hole, no merging is possible. If it does not, - * try to absorb its successor into it and free the successor's table entry. - */ - if ( (next_ptr = hp->h_next) == NIL_HOLE) return; - if (hp->h_base + hp->h_len == next_ptr->h_base) { - hp->h_len += next_ptr->h_len; /* first one gets second one's mem */ - del_slot(hp, next_ptr); - } else { - hp = next_ptr; - } - - /* If 'hp' now points to the last hole, return; otherwise, try to absorb its - * successor into it. - */ - if ( (next_ptr = hp->h_next) == NIL_HOLE) return; - if (hp->h_base + hp->h_len == next_ptr->h_base) { - hp->h_len += next_ptr->h_len; - del_slot(hp, next_ptr); - } -} - -/*===========================================================================* - * mem_init * - *===========================================================================*/ -PUBLIC void mem_init(chunks, free) -struct memory *chunks; /* list of free memory chunks */ -phys_clicks *free; /* memory size summaries */ -{ -/* Initialize hole lists. There are two lists: 'hole_head' points to a linked - * list of all the holes (unused memory) in the system; 'free_slots' points to - * a linked list of table entries that are not in use. Initially, the former - * list has one entry for each chunk of physical memory, and the second - * list links together the remaining table slots. As memory becomes more - * fragmented in the course of time (i.e., the initial big holes break up into - * smaller holes), new table slots are needed to represent them. These slots - * are taken from the list headed by 'free_slots'. - */ - int i; - register struct hole *hp; - - /* Put all holes on the free list. */ - for (hp = &hole[0]; hp < &hole[_NR_HOLES]; hp++) { - hp->h_next = hp + 1; - hp->h_base = hp->h_len = 0; - } - hole[_NR_HOLES-1].h_next = NIL_HOLE; - hole_head = NIL_HOLE; - free_slots = &hole[0]; - - /* Use the chunks of physical memory to allocate holes. */ - *free = 0; - for (i=NR_MEMS-1; i>=0; i--) { - if (chunks[i].size > 0) { - free_mem(chunks[i].base, chunks[i].size); - *free += chunks[i].size; -#if ENABLE_SWAP - if (swap_base < chunks[i].base + chunks[i].size) - swap_base = chunks[i].base + chunks[i].size; -#endif - } - } - -#if ENABLE_SWAP - /* The swap area is represented as a hole above and separate of regular - * memory. A hole at the size of the swap file is allocated on "swapon". - */ - swap_base++; /* make separate */ - swap_maxsize = 0 - swap_base; /* maximum we can possibly use */ -#endif -} - -/*===========================================================================* - * mem_holes_copy * - *===========================================================================*/ -PUBLIC int mem_holes_copy(struct hole *holecopies, size_t *bytes, u32_t *hi) -{ - if(*bytes < sizeof(hole)) return ENOSPC; - memcpy(holecopies, hole, sizeof(hole)); - *bytes = sizeof(hole); - *hi = high_watermark; - return OK; -} - -#define NR_DMA 16 - -PRIVATE struct dmatab -{ - int dt_flags; - endpoint_t dt_proc; - phys_bytes dt_base; - phys_bytes dt_size; - phys_clicks dt_seg_base; - phys_clicks dt_seg_size; -} dmatab[NR_DMA]; - -#define DTF_INUSE 1 -#define DTF_RELEASE_DMA 2 -#define DTF_RELEASE_SEG 4 - -PRIVATE endpoint_t iommu_proc_e= ANY; - -/*===========================================================================* - * do_adddma * - *===========================================================================*/ -PUBLIC int do_adddma() -{ - endpoint_t req_proc_e, target_proc_e; - int i, proc_n; - phys_bytes base, size; - struct mproc *rmp; - - if (mp->mp_effuid != SUPER_USER) - return EPERM; - - req_proc_e= m_in.m_source; - target_proc_e= m_in.m2_i1; - base= m_in.m2_l1; - size= m_in.m2_l2; - - iommu_proc_e= req_proc_e; - - /* Find empty slot */ - for (i= 0; i= NR_DMA) - { - printf("pm:do_adddma: dma table full\n"); - for (i= 0; imp_flags |= HAS_DMA; - - dmatab[i].dt_flags= DTF_INUSE; - dmatab[i].dt_proc= target_proc_e; - dmatab[i].dt_base= base; - dmatab[i].dt_size= size; - - return OK; -} - -/*===========================================================================* - * do_deldma * - *===========================================================================*/ -PUBLIC int do_deldma() -{ - endpoint_t req_proc_e, target_proc_e; - int i, j, proc_n; - phys_bytes base, size; - struct mproc *rmp; - - if (mp->mp_effuid != SUPER_USER) - return EPERM; - - req_proc_e= m_in.m_source; - target_proc_e= m_in.m2_i1; - base= m_in.m2_l1; - size= m_in.m2_l2; - - iommu_proc_e= req_proc_e; - - /* Find slot */ - for (i= 0; i= NR_DMA) - { - printf("pm:do_deldma: slot not found\n"); - return ESRCH; - } - - if (dmatab[i].dt_flags & DTF_RELEASE_SEG) - { - /* Check if we have to release the segment */ - for (j= 0; j= NR_DMA) - { - /* Last segment */ - free_mem(dmatab[i].dt_seg_base, - dmatab[i].dt_seg_size); - } - } - - dmatab[i].dt_flags &= ~DTF_INUSE; - - return OK; -} - -/*===========================================================================* - * do_getdma * - *===========================================================================*/ -PUBLIC int do_getdma() -{ - endpoint_t req_proc_e, target_proc_e; - int i, proc_n; - phys_bytes base, size; - struct mproc *rmp; - - if (mp->mp_effuid != SUPER_USER) - return EPERM; - - req_proc_e= m_in.m_source; - iommu_proc_e= req_proc_e; - - /* Find slot to report */ - for (i= 0; imp_reply.m2_i1= dmatab[i].dt_proc; - mp->mp_reply.m2_l1= dmatab[i].dt_base; - mp->mp_reply.m2_l2= dmatab[i].dt_size; - - return OK; - } - - /* Nothing */ - return EAGAIN; -} - - - -/*===========================================================================* - * release_dma * - *===========================================================================*/ -PUBLIC void release_dma(proc_e, base, size) -endpoint_t proc_e; -phys_clicks base; -phys_clicks size; -{ - int i, found_one;; - - found_one= FALSE; - for (i= 0; i>= CLICK_SHIFT; - if (size > swap_maxsize) size = swap_maxsize; - if (size > 0) free_mem(swap_base, (phys_clicks) size); - return(OK); -} - -/*===========================================================================* - * swap_off * - *===========================================================================*/ -PUBLIC int swap_off() -{ -/* Turn swapping off. */ - struct mproc *rmp; - struct hole *hp, *prev_ptr; - - if (swap_fd == -1) return(OK); /* can't turn off what isn't on */ - - /* Put all swapped out processes on the inswap queue and swap in. */ - for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) { - if (rmp->mp_flags & ONSWAP) swap_inqueue(rmp); - } - swap_in(); - - /* All in memory? */ - for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) { - if (rmp->mp_flags & ONSWAP) return(ENOMEM); - } - - /* Yes. Remove the swap hole and close the swap file descriptor. */ - for (hp = hole_head; hp != NIL_HOLE; prev_ptr = hp, hp = hp->h_next) { - if (hp->h_base >= swap_base) { - del_slot(prev_ptr, hp); - hp = hole_head; - } - } - close(swap_fd); - swap_fd = -1; - return(OK); -} - -/*===========================================================================* - * swap_inqueue * - *===========================================================================*/ -PUBLIC void swap_inqueue(rmp) -register struct mproc *rmp; /* process to add to the queue */ -{ -/* Put a swapped out process on the queue of processes to be swapped in. This - * happens when such a process gets a signal, or if a reply message must be - * sent, like when a process doing a wait() has a child that exits. - */ - struct mproc **pmp; - - if (rmp->mp_flags & SWAPIN) return; /* already queued */ - - - for (pmp = &in_queue; *pmp != NULL; pmp = &(*pmp)->mp_swapq) {} - *pmp = rmp; - rmp->mp_swapq = NULL; - rmp->mp_flags |= SWAPIN; -} - -/*===========================================================================* - * swap_in * - *===========================================================================*/ -PUBLIC void swap_in() -{ -/* Try to swap in a process on the inswap queue. We want to send it a message, - * interrupt it, or something. - */ - struct mproc **pmp, *rmp; - phys_clicks old_base, new_base, size; - off_t off; - int proc_nr; - - pmp = &in_queue; - while ((rmp = *pmp) != NULL) { - proc_nr = (rmp - mproc); - size = rmp->mp_seg[S].mem_vir + rmp->mp_seg[S].mem_len - - rmp->mp_seg[D].mem_vir; - - if (!(rmp->mp_flags & SWAPIN)) { - /* Guess it got killed. (Queue is cleaned here.) */ - *pmp = rmp->mp_swapq; - continue; - } else - if ((new_base = alloc_mem(size)) == NO_MEM) { - /* No memory for this one, try the next. */ - pmp = &rmp->mp_swapq; - } else { - /* We've found memory. Update map and swap in. */ - old_base = rmp->mp_seg[D].mem_phys; - rmp->mp_seg[D].mem_phys = new_base; - rmp->mp_seg[S].mem_phys = rmp->mp_seg[D].mem_phys + - (rmp->mp_seg[S].mem_vir - rmp->mp_seg[D].mem_vir); - sys_newmap(rmp->mp_endpoint, rmp->mp_seg); - off = swap_offset + ((off_t) (old_base-swap_base)<mp_endpoint, D, (phys_bytes)size << CLICK_SHIFT); - free_mem(old_base, size); - rmp->mp_flags &= ~(ONSWAP|SWAPIN); - *pmp = rmp->mp_swapq; - check_pending(rmp); /* a signal may have waked this one */ - } - } -} - -/*===========================================================================* - * swap_out * - *===========================================================================*/ -PRIVATE int swap_out() -{ -/* Try to find a process that can be swapped out. Candidates are those blocked - * on a system call that PM handles, like wait(), pause() or sigsuspend(). - */ - struct mproc *rmp; - struct hole *hp, *prev_ptr; - phys_clicks old_base, new_base, size; - off_t off; - int proc_nr; - - rmp = outswap; - do { - if (++rmp == &mproc[NR_PROCS]) rmp = &mproc[0]; - - /* A candidate? */ - if (!(rmp->mp_flags & (PAUSED | WAITING | SIGSUSPENDED))) continue; - - /* Already on swap or otherwise to be avoided? */ - if (rmp->mp_flags & (DONT_SWAP | TRACED | REPLY | ONSWAP)) continue; - - /* Got one, find a swap hole and swap it out. */ - proc_nr = (rmp - mproc); - size = rmp->mp_seg[S].mem_vir + rmp->mp_seg[S].mem_len - - rmp->mp_seg[D].mem_vir; - - prev_ptr = NIL_HOLE; - for (hp = hole_head; hp != NIL_HOLE; prev_ptr = hp, hp = hp->h_next) { - if (hp->h_base >= swap_base && hp->h_len >= size) break; - } - if (hp == NIL_HOLE) continue; /* oops, not enough swapspace */ - new_base = hp->h_base; - hp->h_base += size; - hp->h_len -= size; - if (hp->h_len == 0) del_slot(prev_ptr, hp); - - off = swap_offset + ((off_t) (new_base - swap_base) << CLICK_SHIFT); - lseek(swap_fd, off, SEEK_SET); - rw_seg(1, swap_fd, rmp->mp_endpoint, D, (phys_bytes)size << CLICK_SHIFT); - old_base = rmp->mp_seg[D].mem_phys; - rmp->mp_seg[D].mem_phys = new_base; - rmp->mp_seg[S].mem_phys = rmp->mp_seg[D].mem_phys + - (rmp->mp_seg[S].mem_vir - rmp->mp_seg[D].mem_vir); - sys_newmap(rmp->mp_endpoint, rmp->mp_seg); - free_mem(old_base, size); - rmp->mp_flags |= ONSWAP; - - outswap = rmp; /* next time start here */ - return(TRUE); - } while (rmp != outswap); - - return(FALSE); /* no candidate found */ -} -#endif /* SWAP */ diff --git a/servers/pm/asynsend.c b/servers/pm/asynsend.c deleted file mode 100644 index de7e5d106..000000000 --- a/servers/pm/asynsend.c +++ /dev/null @@ -1,90 +0,0 @@ - -#include "pm.h" - -#define ASYN_NR 100 -PRIVATE asynmsg_t msgtable[ASYN_NR]; -PRIVATE int first_slot= 0, next_slot= 0; - -PUBLIC int asynsend(dst, mp) -endpoint_t dst; -message *mp; -{ - int r, src_ind, dst_ind; - unsigned flags; - - /* Update first_slot */ - for (; first_slot < next_slot; first_slot++) - { - flags= msgtable[first_slot].flags; - if ((flags & (AMF_VALID|AMF_DONE)) == (AMF_VALID|AMF_DONE)) - { - if (msgtable[first_slot].result != OK) - { - printf( - "asynsend: found completed entry %d with error %d\n", - first_slot, - msgtable[first_slot].result); - } - continue; - } - if (flags != AMF_EMPTY) - break; - } - - if (first_slot >= next_slot) - { - /* Reset first_slot and next_slot */ - next_slot= first_slot= 0; - } - - if (next_slot >= ASYN_NR) - { - /* Tell the kernel to stop processing */ - r= senda(NULL, 0); - if (r != OK) - panic(__FILE__, "asynsend: senda failed", r); - - dst_ind= 0; - for (src_ind= first_slot; src_ind= ASYN_NR) - panic(__FILE__, "asynsend: msgtable full", NO_NUM); - } - - msgtable[next_slot].dst= dst; - msgtable[next_slot].msg= *mp; - msgtable[next_slot].flags= AMF_VALID; /* Has to be last. The kernel - * scans this table while we - * are sleeping. - */ - next_slot++; - - /* Tell the kernel to rescan the table */ - return senda(msgtable+first_slot, next_slot-first_slot); -} - diff --git a/servers/pm/break.c b/servers/pm/break.c index cf87dfe0e..b2afdf823 100644 --- a/servers/pm/break.c +++ b/servers/pm/break.c @@ -1,192 +1,20 @@ -/* The MINIX model of memory allocation reserves a fixed amount of memory for - * the combined text, data, and stack segments. The amount used for a child - * process created by FORK is the same as the parent had. If the child does - * an EXEC later, the new size is taken from the header of the file EXEC'ed. - * - * The layout in memory consists of the text segment, followed by the data - * segment, followed by a gap (unused memory), followed by the stack segment. - * The data segment grows upward and the stack grows downward, so each can - * take memory from the gap. If they meet, the process must be killed. The - * procedures in this file deal with the growth of the data and stack segments. - * - * The entry points into this file are: - * do_brk: BRK/SBRK system calls to grow or shrink the data segment - * adjust: see if a proposed segment adjustment is allowed - * size_ok: see if the segment sizes are feasible (i86 only) - */ #include "pm.h" -#include -#include "mproc.h" #include "param.h" +#include "glo.h" +#include "mproc.h" -#define DATA_CHANGED 1 /* flag value when data segment size changed */ -#define STACK_CHANGED 2 /* flag value when stack size changed */ +#include /*===========================================================================* * do_brk * *===========================================================================*/ PUBLIC int do_brk() { -/* Entry point to brk(addr) system call. real_brk() does the real work, - * as that is called from elsewhere too. - */ int r; - r = real_brk(mp, (vir_bytes) m_in.addr); +/* Entry point to brk(addr) system call. */ + r = vm_brk(mp->mp_endpoint, m_in.addr); mp->mp_reply.reply_ptr = (r == OK ? m_in.addr : (char *) -1); return r; } -/*===========================================================================* - * do_brk * - *===========================================================================*/ -PUBLIC int real_brk(struct mproc *rmp, vir_bytes v) -{ -/* Perform the brk(addr) system call. - * - * The call is complicated by the fact that on some machines (e.g., 8088), - * the stack pointer can grow beyond the base of the stack segment without - * anybody noticing it. - * The parameter, 'addr' is the new virtual address in D space. - * - * This call can also be performed on PM itself from brk() in misc.c. - */ - int r; - vir_bytes new_sp; - vir_clicks new_clicks; - - new_clicks = (vir_clicks) ( ((long) v + CLICK_SIZE - 1) >> CLICK_SHIFT); - if (new_clicks < rmp->mp_seg[D].mem_vir) { - rmp->mp_reply.reply_ptr = (char *) -1; - return(ENOMEM); - } - new_clicks -= rmp->mp_seg[D].mem_vir; - if ((r=get_stack_ptr(rmp->mp_endpoint, &new_sp)) != OK) /* get sp value */ - panic(__FILE__,"couldn't get stack pointer", r); - r = adjust(rmp, new_clicks, new_sp); - return(r); /* return new address or -1 */ -} - -/*===========================================================================* - * adjust * - *===========================================================================*/ -PUBLIC int adjust(rmp, data_clicks, sp) -register struct mproc *rmp; /* whose memory is being adjusted? */ -vir_clicks data_clicks; /* how big is data segment to become? */ -vir_bytes sp; /* new value of sp */ -{ -/* See if data and stack segments can coexist, adjusting them if need be. - * Memory is never allocated or freed. Instead it is added or removed from the - * gap between data segment and stack segment. If the gap size becomes - * negative, the adjustment of data or stack fails and ENOMEM is returned. - */ - - register struct mem_map *mem_sp, *mem_dp; - vir_clicks sp_click, gap_base, lower, old_clicks; - int changed, r, ft; - long base_of_stack, delta; /* longs avoid certain problems */ - - mem_dp = &rmp->mp_seg[D]; /* pointer to data segment map */ - mem_sp = &rmp->mp_seg[S]; /* pointer to stack segment map */ - changed = 0; /* set when either segment changed */ - - /* See if stack size has gone negative (i.e., sp too close to 0xFFFF...) */ - base_of_stack = (long) mem_sp->mem_vir + (long) mem_sp->mem_len; - sp_click = sp >> CLICK_SHIFT; /* click containing sp */ - if (sp_click >= base_of_stack) - { - return(ENOMEM); /* sp too high */ - } - - /* Compute size of gap between stack and data segments. */ - delta = (long) mem_sp->mem_vir - (long) sp_click; - lower = (delta > 0 ? sp_click : mem_sp->mem_vir); - - /* Add a safety margin for future stack growth. Impossible to do right. */ -#define SAFETY_BYTES (384 * sizeof(char *)) -#define SAFETY_CLICKS ((SAFETY_BYTES + CLICK_SIZE - 1) / CLICK_SIZE) - gap_base = mem_dp->mem_vir + data_clicks + SAFETY_CLICKS; - if (lower < gap_base) - { - return(ENOMEM); /* data and stack collided */ - } - - /* Update data length (but not data orgin) on behalf of brk() system call. */ - old_clicks = mem_dp->mem_len; - if (data_clicks != mem_dp->mem_len) { - mem_dp->mem_len = data_clicks; - changed |= DATA_CHANGED; - } - - /* Update stack length and origin due to change in stack pointer. */ - if (delta > 0) { - mem_sp->mem_vir -= delta; - mem_sp->mem_phys -= delta; - mem_sp->mem_len += delta; - changed |= STACK_CHANGED; - } - - /* Do the new data and stack segment sizes fit in the address space? */ - ft = (rmp->mp_flags & SEPARATE); -#if (CHIP == INTEL && _WORD_SIZE == 2) - r = size_ok(ft, rmp->mp_seg[T].mem_len, rmp->mp_seg[D].mem_len, - rmp->mp_seg[S].mem_len, rmp->mp_seg[D].mem_vir, rmp->mp_seg[S].mem_vir); -#else - r = (rmp->mp_seg[D].mem_vir + rmp->mp_seg[D].mem_len > - rmp->mp_seg[S].mem_vir) ? ENOMEM : OK; -#endif - if (r == OK) { - int r2; - if (changed && (r2=sys_newmap(rmp->mp_endpoint, rmp->mp_seg)) != OK) - panic(__FILE__,"couldn't sys_newmap in adjust", r2); - return(OK); - } - - /* New sizes don't fit or require too many page/segment registers. Restore.*/ - if (changed & DATA_CHANGED) mem_dp->mem_len = old_clicks; - if (changed & STACK_CHANGED) { - mem_sp->mem_vir += delta; - mem_sp->mem_phys += delta; - mem_sp->mem_len -= delta; - } - return(ENOMEM); -} - -#if (CHIP == INTEL && _WORD_SIZE == 2) -/*===========================================================================* - * size_ok * - *===========================================================================*/ -PUBLIC int size_ok(file_type, tc, dc, sc, dvir, s_vir) -int file_type; /* SEPARATE or 0 */ -vir_clicks tc; /* text size in clicks */ -vir_clicks dc; /* data size in clicks */ -vir_clicks sc; /* stack size in clicks */ -vir_clicks dvir; /* virtual address for start of data seg */ -vir_clicks s_vir; /* virtual address for start of stack seg */ -{ -/* Check to see if the sizes are feasible and enough segmentation registers - * exist. On a machine with eight 8K pages, text, data, stack sizes of - * (32K, 16K, 16K) will fit, but (33K, 17K, 13K) will not, even though the - * former is bigger (64K) than the latter (63K). Even on the 8088 this test - * is needed, since the data and stack may not exceed 4096 clicks. - * Note this is not used for 32-bit Intel Minix, the test is done in-line. - */ - - int pt, pd, ps; /* segment sizes in pages */ - - pt = ( (tc << CLICK_SHIFT) + PAGE_SIZE - 1)/PAGE_SIZE; - pd = ( (dc << CLICK_SHIFT) + PAGE_SIZE - 1)/PAGE_SIZE; - ps = ( (sc << CLICK_SHIFT) + PAGE_SIZE - 1)/PAGE_SIZE; - - if (file_type == SEPARATE) { - if (pt > MAX_PAGES || pd + ps > MAX_PAGES) return(ENOMEM); - } else { - if (pt + pd + ps > MAX_PAGES) return(ENOMEM); - } - - if (dvir + dc > s_vir) return(ENOMEM); - - return(OK); -} -#endif - diff --git a/servers/pm/const.h b/servers/pm/const.h index 200dfe837..886380a7c 100644 --- a/servers/pm/const.h +++ b/servers/pm/const.h @@ -1,16 +1,5 @@ /* Constants used by the Process Manager. */ -#define NO_MEM ((phys_clicks) 0) /* returned by alloc_mem() with mem is up */ - -#if (CHIP == INTEL && _WORD_SIZE == 2) -/* These definitions are used in size_ok and are not needed for 386. - * The 386 segment granularity is 1 for segments smaller than 1M and 4096 - * above that. - */ -#define PAGE_SIZE 16 /* how many bytes in a page (s.b.HCLICK_SIZE)*/ -#define MAX_PAGES 4096 /* how many pages in the virtual addr space */ -#endif - #define NR_PIDS 30000 /* process ids range from 0 to NR_PIDS-1. * (magic constant: some old applications use * a 'short' instead of pid_t.) diff --git a/servers/pm/exec.c b/servers/pm/exec.c index 0190bb7b9..62dd5f678 100644 --- a/servers/pm/exec.c +++ b/servers/pm/exec.c @@ -23,16 +23,13 @@ #include #include #include +#include #include #include #include #include "mproc.h" #include "param.h" -FORWARD _PROTOTYPE( int new_mem, (struct mproc *rmp, struct mproc *sh_mp, - vir_bytes text_bytes, vir_bytes data_bytes, vir_bytes bss_bytes, - vir_bytes stk_bytes, phys_bytes tot_bytes) ); - #define ESCRIPT (-2000) /* Returned by read_header for a #! script. */ #define PTRSIZE sizeof(char *) /* Size of pointers in argv[] and envp[]. */ @@ -69,12 +66,12 @@ PUBLIC int do_exec() *===========================================================================*/ PUBLIC int exec_newmem() { - int r, proc_e, proc_n, allow_setuid; - vir_bytes stack_top; - vir_clicks tc, dc, sc, totc, dvir, s_vir; - struct mproc *rmp, *sh_mp; + int proc_e, proc_n, allow_setuid; char *ptr; + struct mproc *rmp; struct exec_newmem args; + int r, flags; + char *stack_top; if (who_e != FS_PROC_NR && who_e != RS_PROC_NR) return EPERM; @@ -86,84 +83,40 @@ PUBLIC int exec_newmem() proc_e); } rmp= &mproc[proc_n]; - ptr= m_in.EXC_NM_PTR; r= sys_datacopy(who_e, (vir_bytes)ptr, SELF, (vir_bytes)&args, sizeof(args)); if (r != OK) panic(__FILE__, "exec_newmem: sys_datacopy failed", r); - /* Check to see if segment sizes are feasible. */ - tc = ((unsigned long) args.text_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; - dc = (args.data_bytes+args.bss_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; - totc = (args.tot_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; - sc = (args.args_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; - if (dc >= totc) return(ENOEXEC); /* stack must be at least 1 click */ + if((r=vm_exec_newmem(proc_e, &args, sizeof(args), &stack_top, &flags)) == OK) { + allow_setuid= 0; /* Do not allow setuid execution */ - dvir = (args.sep_id ? 0 : tc); - s_vir = dvir + (totc - sc); -#if (CHIP == INTEL && _WORD_SIZE == 2) - r = size_ok(*ft, tc, dc, sc, dvir, s_vir); -#else - r = (dvir + dc > s_vir) ? ENOMEM : OK; -#endif - if (r != OK) - return r; + if ((rmp->mp_flags & TRACED) == 0) { + /* Okay, setuid execution is allowed */ + allow_setuid= 1; + rmp->mp_effuid = args.new_uid; + rmp->mp_effgid = args.new_gid; + } - /* Can the process' text be shared with that of one already running? */ - sh_mp = find_share(rmp, args.st_ino, args.st_dev, args.st_ctime); + /* System will save command line for debugging, ps(1) output, etc. */ + strncpy(rmp->mp_name, args.progname, PROC_NAME_LEN-1); + rmp->mp_name[PROC_NAME_LEN-1] = '\0'; - /* Allocate new memory and release old memory. Fix map and tell - * kernel. - */ - r = new_mem(rmp, sh_mp, args.text_bytes, args.data_bytes, - args.bss_bytes, args.args_bytes, args.tot_bytes); - if (r != OK) return(r); + /* Save offset to initial argc (for ps) */ + rmp->mp_procargs = (vir_bytes) stack_top - args.args_bytes; - rmp->mp_flags |= PARTIAL_EXEC; /* Kill process if something goes - * wrong after this point. - */ + /* Kill process if something goes wrong after this point. */ + rmp->mp_flags |= PARTIAL_EXEC; - /* Save file identification to allow it to be shared. */ - rmp->mp_ino = args.st_ino; - rmp->mp_dev = args.st_dev; - rmp->mp_ctime = args.st_ctime; - - stack_top= ((vir_bytes)rmp->mp_seg[S].mem_vir << CLICK_SHIFT) + - ((vir_bytes)rmp->mp_seg[S].mem_len << CLICK_SHIFT); - - /* Save offset to initial argc (for ps) */ - rmp->mp_procargs = stack_top - args.args_bytes; - - /* set/clear separate I&D flag */ - if (args.sep_id) - rmp->mp_flags |= SEPARATE; - else - rmp->mp_flags &= ~SEPARATE; - - allow_setuid= 0; /* Do not allow setuid execution */ - if ((rmp->mp_flags & TRACED) == 0) { - /* Okay, setuid execution is allowed */ - allow_setuid= 1; - rmp->mp_effuid = args.new_uid; - rmp->mp_effgid = args.new_gid; + mp->mp_reply.reply_res2= (vir_bytes) stack_top; + mp->mp_reply.reply_res3= flags; + if (allow_setuid) + mp->mp_reply.reply_res3 |= EXC_NM_RF_ALLOW_SETUID; } - - /* System will save command line for debugging, ps(1) output, etc. */ - strncpy(rmp->mp_name, args.progname, PROC_NAME_LEN-1); - rmp->mp_name[PROC_NAME_LEN-1] = '\0'; - - mp->mp_reply.reply_res2= stack_top; - mp->mp_reply.reply_res3= 0; - if (!sh_mp) /* Load text if sh_mp = NULL */ - mp->mp_reply.reply_res3 |= EXC_NM_RF_LOAD_TEXT; - if (allow_setuid) - mp->mp_reply.reply_res3 |= EXC_NM_RF_ALLOW_SETUID; - - return OK; + return r; } - /*===========================================================================* * do_execrestart * *===========================================================================*/ @@ -239,140 +192,3 @@ int result; if (rmp->mp_flags & TRACED) check_sig(rmp->mp_pid, SIGTRAP); } -/*===========================================================================* - * find_share * - *===========================================================================*/ -PUBLIC struct mproc *find_share(mp_ign, ino, dev, ctime) -struct mproc *mp_ign; /* process that should not be looked at */ -ino_t ino; /* parameters that uniquely identify a file */ -dev_t dev; -time_t ctime; -{ -/* Look for a process that is the file in execution. Don't - * accidentally "find" mp_ign, because it is the process on whose behalf this - * call is made. - */ - struct mproc *sh_mp; - for (sh_mp = &mproc[0]; sh_mp < &mproc[NR_PROCS]; sh_mp++) { - - if (!(sh_mp->mp_flags & SEPARATE)) continue; - if (sh_mp == mp_ign) continue; - if (sh_mp->mp_ino != ino) continue; - if (sh_mp->mp_dev != dev) continue; - if (sh_mp->mp_ctime != ctime) continue; - return sh_mp; - } - return(NULL); -} - -/*===========================================================================* - * new_mem * - *===========================================================================*/ -PRIVATE int new_mem(rmp, sh_mp, text_bytes, data_bytes, - bss_bytes,stk_bytes,tot_bytes) -struct mproc *rmp; /* process to get a new memory map */ -struct mproc *sh_mp; /* text can be shared with this process */ -vir_bytes text_bytes; /* text segment size in bytes */ -vir_bytes data_bytes; /* size of initialized data in bytes */ -vir_bytes bss_bytes; /* size of bss in bytes */ -vir_bytes stk_bytes; /* size of initial stack segment in bytes */ -phys_bytes tot_bytes; /* total memory to allocate, including gap */ -{ -/* Allocate new memory and release the old memory. Change the map and report - * the new map to the kernel. Zero the new core image's bss, gap and stack. - */ - - vir_clicks text_clicks, data_clicks, gap_clicks, stack_clicks, tot_clicks; - phys_clicks new_base; - phys_bytes bytes, base, bss_offset; - int s, r2; - - /* No need to allocate text if it can be shared. */ - if (sh_mp != NULL) text_bytes = 0; - - /* Allow the old data to be swapped out to make room. (Which is really a - * waste of time, because we are going to throw it away anyway.) - */ - rmp->mp_flags |= WAITING; - - /* Acquire the new memory. Each of the 4 parts: text, (data+bss), gap, - * and stack occupies an integral number of clicks, starting at click - * boundary. The data and bss parts are run together with no space. - */ - text_clicks = ((unsigned long) text_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; - data_clicks = (data_bytes + bss_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; - stack_clicks = (stk_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; - tot_clicks = (tot_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; - gap_clicks = tot_clicks - data_clicks - stack_clicks; - if ( (int) gap_clicks < 0) return(ENOMEM); - - /* Try to allocate memory for the new process. */ - new_base = alloc_mem(text_clicks + tot_clicks); - if (new_base == NO_MEM) return(ENOMEM); - - /* We've got memory for the new core image. Release the old one. */ - if (find_share(rmp, rmp->mp_ino, rmp->mp_dev, rmp->mp_ctime) == NULL) { - /* No other process shares the text segment, so free it. */ - free_mem(rmp->mp_seg[T].mem_phys, rmp->mp_seg[T].mem_len); - } - /* Free the data and stack segments. */ - free_mem(rmp->mp_seg[D].mem_phys, - rmp->mp_seg[S].mem_vir + rmp->mp_seg[S].mem_len - rmp->mp_seg[D].mem_vir); - - /* We have now passed the point of no return. The old core image has been - * forever lost, memory for a new core image has been allocated. Set up - * and report new map. - */ - if (sh_mp != NULL) { - /* Share the text segment. */ - rmp->mp_seg[T] = sh_mp->mp_seg[T]; - } else { - rmp->mp_seg[T].mem_phys = new_base; - rmp->mp_seg[T].mem_vir = 0; - rmp->mp_seg[T].mem_len = text_clicks; - - if (text_clicks > 0) - { - /* Zero the last click of the text segment. Otherwise the - * part of that click may remain unchanged. - */ - base = (phys_bytes)(new_base+text_clicks-1) << CLICK_SHIFT; - if ((s= sys_memset(0, base, CLICK_SIZE)) != OK) - panic(__FILE__, "new_mem: sys_memset failed", s); - } - } - rmp->mp_seg[D].mem_phys = new_base + text_clicks; - rmp->mp_seg[D].mem_vir = 0; - rmp->mp_seg[D].mem_len = data_clicks; - rmp->mp_seg[S].mem_phys = rmp->mp_seg[D].mem_phys + data_clicks + gap_clicks; - rmp->mp_seg[S].mem_vir = rmp->mp_seg[D].mem_vir + data_clicks + gap_clicks; - rmp->mp_seg[S].mem_len = stack_clicks; - -#if (CHIP == M68000) - rmp->mp_seg[T].mem_vir = 0; - rmp->mp_seg[D].mem_vir = rmp->mp_seg[T].mem_len; - rmp->mp_seg[S].mem_vir = rmp->mp_seg[D].mem_vir - + rmp->mp_seg[D].mem_len + gap_clicks; -#endif - - if((r2=sys_newmap(rmp->mp_endpoint, rmp->mp_seg)) != OK) { - /* report new map to the kernel */ - panic(__FILE__,"sys_newmap failed", r2); - } - - /* The old memory may have been swapped out, but the new memory is real. */ - rmp->mp_flags &= ~(WAITING|ONSWAP|SWAPIN); - - /* Zero the bss, gap, and stack segment. */ - bytes = (phys_bytes)(data_clicks + gap_clicks + stack_clicks) << CLICK_SHIFT; - base = (phys_bytes) rmp->mp_seg[D].mem_phys << CLICK_SHIFT; - bss_offset = (data_bytes >> CLICK_SHIFT) << CLICK_SHIFT; - base += bss_offset; - bytes -= bss_offset; - - if ((s=sys_memset(0, base, bytes)) != OK) { - panic(__FILE__,"new_mem can't zero", s); - } - - return(OK); -} diff --git a/servers/pm/forkexit.c b/servers/pm/forkexit.c index 135247273..63656ad6b 100644 --- a/servers/pm/forkexit.c +++ b/servers/pm/forkexit.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include "mproc.h" @@ -35,12 +36,10 @@ PUBLIC int do_fork() /* The process pointed to by 'mp' has forked. Create a child process. */ register struct mproc *rmp; /* pointer to parent */ register struct mproc *rmc; /* pointer to child */ - int child_nr, s; - phys_clicks prog_clicks, child_base; - phys_bytes prog_bytes, parent_abs, child_abs; /* Intel only */ pid_t new_pid; static int next_child; - int n = 0, r; + int n = 0, r, s; + endpoint_t child_ep; /* If tables might fill up during FORK, don't even start since recovery half * way through is such a nuisance. @@ -53,20 +52,6 @@ PUBLIC int do_fork() return(EAGAIN); } - /* Determine how much memory to allocate. Only the data and stack need to - * be copied, because the text segment is either shared or of zero length. - */ - prog_clicks = (phys_clicks) rmp->mp_seg[S].mem_len; - prog_clicks += (rmp->mp_seg[S].mem_vir - rmp->mp_seg[D].mem_vir); - prog_bytes = (phys_bytes) prog_clicks << CLICK_SHIFT; - if ( (child_base = alloc_mem(prog_clicks)) == NO_MEM) return(ENOMEM); - - /* Create a copy of the parent's core image for the child. */ - child_abs = (phys_bytes) child_base << CLICK_SHIFT; - parent_abs = (phys_bytes) rmp->mp_seg[D].mem_phys << CLICK_SHIFT; - s = sys_abscopy(parent_abs, child_abs, prog_bytes); - if (s < 0) panic(__FILE__,"do_fork can't copy", s); - /* Find a slot in 'mproc' for the child process. A slot must exist. */ do { next_child = (next_child+1) % NR_PROCS; @@ -78,36 +63,31 @@ PUBLIC int do_fork() || (mproc[next_child].mp_flags & IN_USE)) panic(__FILE__,"do_fork finds wrong child slot", next_child); + /* Memory part of the forking. */ + if((s=vm_fork(rmp->mp_endpoint, next_child, &child_ep)) != OK) { + printf("PM: vm_fork failed: %d\n", s); + return s; + } + + /* PM may not fail fork after call to vm_fork(), as VM calls sys_fork(). */ + rmc = &mproc[next_child]; /* Set up the child and its memory map; copy its 'mproc' slot from parent. */ - child_nr = (int)(rmc - mproc); /* slot number of the child */ procs_in_use++; *rmc = *rmp; /* copy parent's process slot to child's */ rmc->mp_parent = who_p; /* record child's parent */ /* inherit only these flags */ - rmc->mp_flags &= (IN_USE|SEPARATE|PRIV_PROC|DONT_SWAP); + rmc->mp_flags &= (IN_USE|PRIV_PROC); rmc->mp_child_utime = 0; /* reset administration */ rmc->mp_child_stime = 0; /* reset administration */ - - /* A separate I&D child keeps the parents text segment. The data and stack - * segments must refer to the new copy. - */ - if (!(rmc->mp_flags & SEPARATE)) rmc->mp_seg[T].mem_phys = child_base; - rmc->mp_seg[D].mem_phys = child_base; - rmc->mp_seg[S].mem_phys = rmc->mp_seg[D].mem_phys + - (rmp->mp_seg[S].mem_vir - rmp->mp_seg[D].mem_vir); rmc->mp_exitstatus = 0; rmc->mp_sigstatus = 0; + rmc->mp_endpoint = child_ep; /* passed back by VM */ /* Find a free pid for the child and put it in the table. */ new_pid = get_free_pid(); rmc->mp_pid = new_pid; /* assign pid to child */ - /* Tell kernel and file system about the (now successful) FORK. */ - if((r=sys_fork(who_e, child_nr, &rmc->mp_endpoint, rmc->mp_seg)) != OK) { - panic(__FILE__,"do_fork can't sys_fork", r); - } - if (rmc->mp_fs_call != PM_IDLE) panic("pm", "do_fork: not idle", rmc->mp_fs_call); rmc->mp_fs_call= PM_FORK; @@ -128,12 +108,11 @@ PUBLIC int do_fork_nb() /* The process pointed to by 'mp' has forked. Create a child process. */ register struct mproc *rmp; /* pointer to parent */ register struct mproc *rmc; /* pointer to child */ - int child_nr, s; - phys_clicks prog_clicks, child_base; - phys_bytes prog_bytes, parent_abs, child_abs; /* Intel only */ + int s; pid_t new_pid; static int next_child; int n = 0, r; + endpoint_t child_ep; /* Only system processes are allowed to use fork_nb */ if (!(mp->mp_flags & PRIV_PROC)) @@ -150,20 +129,6 @@ PUBLIC int do_fork_nb() return(EAGAIN); } - /* Determine how much memory to allocate. Only the data and stack need to - * be copied, because the text segment is either shared or of zero length. - */ - prog_clicks = (phys_clicks) rmp->mp_seg[S].mem_len; - prog_clicks += (rmp->mp_seg[S].mem_vir - rmp->mp_seg[D].mem_vir); - prog_bytes = (phys_bytes) prog_clicks << CLICK_SHIFT; - if ( (child_base = alloc_mem(prog_clicks)) == NO_MEM) return(ENOMEM); - - /* Create a copy of the parent's core image for the child. */ - child_abs = (phys_bytes) child_base << CLICK_SHIFT; - parent_abs = (phys_bytes) rmp->mp_seg[D].mem_phys << CLICK_SHIFT; - s = sys_abscopy(parent_abs, child_abs, prog_bytes); - if (s < 0) panic(__FILE__,"do_fork can't copy", s); - /* Find a slot in 'mproc' for the child process. A slot must exist. */ do { next_child = (next_child+1) % NR_PROCS; @@ -175,36 +140,26 @@ PUBLIC int do_fork_nb() || (mproc[next_child].mp_flags & IN_USE)) panic(__FILE__,"do_fork finds wrong child slot", next_child); + if((s=vm_fork(rmp->mp_endpoint, next_child, &child_ep)) != OK) { + printf("PM: vm_fork failed: %d\n", s); + return s; + } + rmc = &mproc[next_child]; /* Set up the child and its memory map; copy its 'mproc' slot from parent. */ - child_nr = (int)(rmc - mproc); /* slot number of the child */ procs_in_use++; *rmc = *rmp; /* copy parent's process slot to child's */ rmc->mp_parent = who_p; /* record child's parent */ /* inherit only these flags */ - rmc->mp_flags &= (IN_USE|SEPARATE|PRIV_PROC|DONT_SWAP); + rmc->mp_flags &= (IN_USE|PRIV_PROC); rmc->mp_child_utime = 0; /* reset administration */ rmc->mp_child_stime = 0; /* reset administration */ - - /* A separate I&D child keeps the parents text segment. The data and stack - * segments must refer to the new copy. - */ - if (!(rmc->mp_flags & SEPARATE)) rmc->mp_seg[T].mem_phys = child_base; - rmc->mp_seg[D].mem_phys = child_base; - rmc->mp_seg[S].mem_phys = rmc->mp_seg[D].mem_phys + - (rmp->mp_seg[S].mem_vir - rmp->mp_seg[D].mem_vir); - rmc->mp_exitstatus = 0; - rmc->mp_sigstatus = 0; + rmc->mp_endpoint = child_ep; /* passed back by VM */ /* Find a free pid for the child and put it in the table. */ new_pid = get_free_pid(); rmc->mp_pid = new_pid; /* assign pid to child */ - /* Tell kernel and file system about the (now successful) FORK. */ - if((r=sys_fork(who_e, child_nr, &rmc->mp_endpoint, rmc->mp_seg)) != OK) { - panic(__FILE__,"do_fork can't sys_fork", r); - } - if (rmc->mp_fs_call != PM_IDLE) panic("pm", "do_fork: not idle", rmc->mp_fs_call); rmc->mp_fs_call= PM_FORK_NB; @@ -271,6 +226,9 @@ int for_trace; * such as copying to/ from the exiting process, before it is gone. */ sys_nice(proc_nr_e, PRIO_STOP); /* stop the process */ + if(vm_willexit(proc_nr_e) != OK) { + panic(__FILE__, "pm_exit: vm_willexit failed", proc_nr_e); + } if (proc_nr_e == INIT_PROC_NR) { @@ -392,7 +350,9 @@ PUBLIC int do_waitpid() /* No qualifying child has exited. Wait for one, unless none exists. */ if (children > 0) { /* At least 1 child meets the pid test exists, but has not exited. */ - if (options & WNOHANG) return(0); /* parent does not want to wait */ + if (options & WNOHANG) { + return(0); /* parent does not want to wait */ + } mp->mp_flags |= WAITING; /* parent wants to wait */ mp->mp_wpid = (pid_t) pidarg; /* save pid for later */ return(SUSPEND); /* do not reply, let it wait */ diff --git a/servers/pm/kputc.c b/servers/pm/kputc.c index b0c53b099..e764581b6 100644 --- a/servers/pm/kputc.c +++ b/servers/pm/kputc.c @@ -15,7 +15,7 @@ #define PRINTPROCS (sizeof(procs)/sizeof(procs[0])) -static char print_buf[80]; /* output is buffered here */ +static char print_buf[800]; /* output is buffered here */ int kputc_use_private_grants= 0; diff --git a/servers/pm/main.c b/servers/pm/main.c index 4a60bd1e7..8f603a7b9 100644 --- a/servers/pm/main.c +++ b/servers/pm/main.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -41,10 +42,6 @@ EXTERN unsigned long calls_stats[NCALLS]; FORWARD _PROTOTYPE( void get_work, (void) ); FORWARD _PROTOTYPE( void pm_init, (void) ); FORWARD _PROTOTYPE( int get_nice_value, (int queue) ); -FORWARD _PROTOTYPE( void get_mem_chunks, (struct memory *mem_chunks) ); -FORWARD _PROTOTYPE( void patch_mem_chunks, (struct memory *mem_chunks, - struct mem_map *map_ptr) ); -FORWARD _PROTOTYPE( void do_x86_vm, (struct memory mem_chunks[NR_MEMS]) ); FORWARD _PROTOTYPE( void send_work, (void) ); FORWARD _PROTOTYPE( void handle_fs_reply, (message *m_ptr) ); @@ -138,7 +135,9 @@ PUBLIC int main() #if ENABLE_SYSCALL_STATS calls_stats[call_nr]++; #endif + result = (*call_vec[call_nr])(); + } break; } @@ -146,10 +145,8 @@ PUBLIC int main() /* Send the results back to the user to indicate completion. */ if (result != SUSPEND) setreply(who_p, result); - swap_in(); /* maybe a process can be swapped in? */ - /* Send out all pending reply messages, including the answer to - * the call just made above. The processes must not be swapped out. + * the call just made above. */ for (proc_nr=0, rmp=mproc; proc_nr < NR_PROCS; proc_nr++, rmp++) { /* In the meantime, the process may have been killed by a @@ -157,7 +154,7 @@ PUBLIC int main() * without the PM realizing it. If the slot is no longer in * use or just a zombie, don't try to reply. */ - if ((rmp->mp_flags & (REPLY | ONSWAP | IN_USE | ZOMBIE)) == + if ((rmp->mp_flags & (REPLY | IN_USE | ZOMBIE)) == (REPLY | IN_USE)) { s=sendnb(rmp->mp_endpoint, &rmp->mp_reply); if (s != OK) { @@ -213,9 +210,6 @@ int result; /* result of call (usually OK or error #) */ rmp->mp_reply.reply_res = result; rmp->mp_flags |= REPLY; /* reply pending */ - - if (rmp->mp_flags & ONSWAP) - swap_inqueue(rmp); /* must swap this process back in */ } /*===========================================================================* @@ -223,6 +217,8 @@ int result; /* result of call (usually OK or error #) */ *===========================================================================*/ PRIVATE void pm_init() { + int failed = 0; + int f = 0; /* Initialize the process manager. * Memory use info is collected from the boot monitor, the kernel, and * all processes compiled into the system image. Initially this information @@ -244,10 +240,7 @@ PRIVATE void pm_init() static char mess_sigs[] = { SIGTERM, SIGHUP, SIGABRT, SIGQUIT }; register struct mproc *rmp; register char *sig_ptr; - phys_clicks total_clicks, minix_clicks, free_clicks; message mess; - struct mem_map mem_map[NR_LOCAL_SEGS]; - struct memory mem_chunks[NR_MEMS]; /* Initialize process table, including timers. */ for (rmp=&mproc[0]; rmp<&mproc[NR_PROCS]; rmp++) { @@ -273,30 +266,25 @@ PRIVATE void pm_init() */ if ((s=sys_getmonparams(monitor_params, sizeof(monitor_params))) != OK) panic(__FILE__,"get monitor params failed",s); - get_mem_chunks(mem_chunks); if ((s=sys_getkinfo(&kinfo)) != OK) panic(__FILE__,"get kernel info failed",s); - /* Get the memory map of the kernel to see how much memory it uses. */ - if ((s=get_mem_map(SYSTASK, mem_map)) != OK) - panic(__FILE__,"couldn't get memory map of SYSTASK",s); - minix_clicks = (mem_map[S].mem_phys+mem_map[S].mem_len)-mem_map[T].mem_phys; - patch_mem_chunks(mem_chunks, mem_map); - /* Initialize PM's process table. Request a copy of the system image table * that is defined at the kernel level to see which slots to fill in. */ if (OK != (s=sys_getimage(image))) panic(__FILE__,"couldn't get image table: %d\n", s); procs_in_use = 0; /* start populating table */ - for (ip = &image[0]; ip < &image[NR_BOOT_PROCS]; ip++) { + for (ip = &image[0]; ip < &image[NR_BOOT_PROCS]; ip++) { if (ip->proc_nr >= 0) { /* task have negative nrs */ procs_in_use += 1; /* found user process */ /* Set process details found in the image table. */ rmp = &mproc[ip->proc_nr]; strncpy(rmp->mp_name, ip->proc_name, PROC_NAME_LEN); +#if 0 rmp->mp_parent = RS_PROC_NR; +#endif rmp->mp_nice = get_nice_value(ip->priority); sigemptyset(&rmp->mp_sig2mess); sigemptyset(&rmp->mp_ignore); @@ -308,7 +296,7 @@ PRIVATE void pm_init() } else { /* system process */ rmp->mp_pid = get_free_pid(); - rmp->mp_flags |= IN_USE | DONT_SWAP | PRIV_PROC; + rmp->mp_flags |= IN_USE | PRIV_PROC; for (sig_ptr = mess_sigs; sig_ptr < mess_sigs+sizeof(mess_sigs); sig_ptr++) @@ -318,14 +306,6 @@ PRIVATE void pm_init() /* Get kernel endpoint identifier. */ rmp->mp_endpoint = ip->endpoint; - /* Get memory map for this process from the kernel. */ - if ((s=get_mem_map(ip->proc_nr, rmp->mp_seg)) != OK) - panic(__FILE__,"couldn't get process entry",s); - if (rmp->mp_seg[T].mem_len != 0) rmp->mp_flags |= SEPARATE; - minix_clicks += rmp->mp_seg[S].mem_phys + - rmp->mp_seg[S].mem_len - rmp->mp_seg[T].mem_phys; - patch_mem_chunks(mem_chunks, rmp->mp_seg); - /* Tell FS about this system process. */ mess.PR_SLOT = ip->proc_nr; mess.PR_PID = rmp->mp_pid; @@ -336,17 +316,19 @@ PRIVATE void pm_init() /* Register proces with ds */ s= ds_publish_u32(rmp->mp_name, rmp->mp_endpoint); if (s != OK) - { - printf( - "pm_init: unable to register '%s' with ds: %d\n", - rmp->mp_name, s); - } + failed++; } } + if(failed > 0) + printf("PM: failed to register %d/%d boot processes\n", + failed, NR_BOOT_PROCS); + /* Override some details. INIT, PM, FS and RS are somewhat special. */ mproc[PM_PROC_NR].mp_pid = PM_PID; /* PM has magic pid */ +#if 0 mproc[RS_PROC_NR].mp_parent = INIT_PROC_NR; /* INIT is root */ +#endif sigfillset(&mproc[PM_PROC_NR].mp_ignore); /* guard against signals */ /* Tell FS that no more system processes follow and synchronize. */ @@ -354,30 +336,12 @@ PRIVATE void pm_init() if (sendrec(FS_PROC_NR, &mess) != OK || mess.m_type != OK) panic(__FILE__,"can't sync up with FS", NO_NUM); -#if ENABLE_BOOTDEV - /* Possibly we must correct the memory chunks for the boot device. */ - if (kinfo.bootdev_size > 0) { - mem_map[T].mem_phys = kinfo.bootdev_base >> CLICK_SHIFT; - mem_map[T].mem_len = 0; - mem_map[D].mem_len = (kinfo.bootdev_size+CLICK_SIZE-1) >> CLICK_SHIFT; - patch_mem_chunks(mem_chunks, mem_map); - } -#endif /* ENABLE_BOOTDEV */ - - /* Withhold some memory from x86 VM */ - do_x86_vm(mem_chunks); - - /* Initialize tables to all physical memory and print memory information. */ - printf("Physical memory:"); - mem_init(mem_chunks, &free_clicks); - total_clicks = minix_clicks + free_clicks; - printf(" total %u KB,", click_to_round_k(total_clicks)); - printf(" system %u KB,", click_to_round_k(minix_clicks)); - printf(" free %u KB.\n", click_to_round_k(free_clicks)); #if (CHIP == INTEL) - uts_val.machine[0] = 'i'; - strcpy(uts_val.machine + 1, itoa(getprocessor())); -#endif + uts_val.machine[0] = 'i'; + strcpy(uts_val.machine + 1, itoa(getprocessor())); +#endif + + if(f > 0) printf("PM: failed to register %d processes with DS.\n", f); } /*===========================================================================* @@ -397,132 +361,24 @@ int queue; /* store mem chunks here */ return nice_val; } -/*===========================================================================* - * get_mem_chunks * - *===========================================================================*/ -PRIVATE void get_mem_chunks(mem_chunks) -struct memory *mem_chunks; /* store mem chunks here */ +void checkme(char *str, int line) { -/* Initialize the free memory list from the 'memory' boot variable. Translate - * the byte offsets and sizes in this list to clicks, properly truncated. - */ - long base, size, limit; - int i; - struct memory *memp; - - /* Obtain and parse memory from system environment. */ - if(env_memory_parse(mem_chunks, NR_MEMS) != OK) - panic(__FILE__,"couldn't obtain memory chunks", NO_NUM); - - /* Round physical memory to clicks. */ - for (i = 0; i < NR_MEMS; i++) { - memp = &mem_chunks[i]; /* next mem chunk is stored here */ - base = mem_chunks[i].base; - size = mem_chunks[i].size; - limit = base + size; - base = (base + CLICK_SIZE-1) & ~(long)(CLICK_SIZE-1); - limit &= ~(long)(CLICK_SIZE-1); - if (limit <= base) { - memp->base = memp->size = 0; - } else { - memp->base = base >> CLICK_SHIFT; - memp->size = (limit - base) >> CLICK_SHIFT; + struct mproc *trmp; + int boned = 0; + int proc_nr; + for (proc_nr=0, trmp=mproc; proc_nr < NR_PROCS; proc_nr++, trmp++) { + if ((trmp->mp_flags & (REPLY | IN_USE | ZOMBIE)) == + (REPLY | IN_USE)) { + int tp; + if(pm_isokendpt(trmp->mp_endpoint, &tp) != OK) { + printf("PM: %s:%d: reply %d to %s is bogus endpoint %d after call %d by %d\n", + str, line, trmp->mp_reply.m_type, + trmp->mp_name, trmp->mp_endpoint, call_nr, who_e); + boned=1; + } + } + if(boned) panic(__FILE__, "corrupt mp_endpoint?", NO_NUM); } - } -} - -/*===========================================================================* - * patch_mem_chunks * - *===========================================================================*/ -PRIVATE void patch_mem_chunks(mem_chunks, map_ptr) -struct memory *mem_chunks; /* store mem chunks here */ -struct mem_map *map_ptr; /* memory to remove */ -{ -/* Remove server memory from the free memory list. The boot monitor - * promises to put processes at the start of memory chunks. The - * tasks all use same base address, so only the first task changes - * the memory lists. The servers and init have their own memory - * spaces and their memory will be removed from the list. - */ - struct memory *memp; - for (memp = mem_chunks; memp < &mem_chunks[NR_MEMS]; memp++) { - if (memp->base == map_ptr[T].mem_phys) { - memp->base += map_ptr[T].mem_len + map_ptr[S].mem_vir; - memp->size -= map_ptr[T].mem_len + map_ptr[S].mem_vir; - break; - } - } - if (memp >= &mem_chunks[NR_MEMS]) - { - panic(__FILE__,"patch_mem_chunks: can't find map in mem_chunks, start", - map_ptr[T].mem_phys); - } -} - -#define PAGE_SIZE 4096 -#define PAGE_DIR_SIZE (1024*PAGE_SIZE) -#define PAGE_TABLE_COVER (1024*PAGE_SIZE) -/*=========================================================================* - * do_x86_vm * - *=========================================================================*/ -PRIVATE void do_x86_vm(mem_chunks) -struct memory mem_chunks[NR_MEMS]; -{ - phys_bytes high, bytes; - phys_clicks clicks, base_click; - unsigned pages; - int i, r; - - /* Compute the highest memory location */ - high= 0; - for (i= 0; i high) - high= mem_chunks[i].base + mem_chunks[i].size; - } - - high <<= CLICK_SHIFT; -#if VERBOSE_VM - printf("do_x86_vm: found high 0x%x\n", high); -#endif - - /* Rounding up */ - high= (high-1+PAGE_DIR_SIZE) & ~(PAGE_DIR_SIZE-1); - - /* The number of pages we need is one for the page directory, enough - * page tables to cover the memory, and one page for alignement. - */ - pages= 1 + (high + PAGE_TABLE_COVER-1)/PAGE_TABLE_COVER + 1; - bytes= pages*PAGE_SIZE; - clicks= (bytes + CLICK_SIZE-1) >> CLICK_SHIFT; - -#if VERBOSE_VM - printf("do_x86_vm: need %d pages\n", pages); - printf("do_x86_vm: need %d bytes\n", bytes); - printf("do_x86_vm: need %d clicks\n", clicks); -#endif - - for (i= 0; i= NR_MEMS) - panic("PM", "not enough memory for VM page tables?", NO_NUM); - base_click= mem_chunks[i].base; - mem_chunks[i].base += clicks; - mem_chunks[i].size -= clicks; - -#if VERBOSE_VM - printf("do_x86_vm: using 0x%x clicks @ 0x%x\n", clicks, base_click); -#endif - r= sys_vm_setbuf(base_click << CLICK_SHIFT, clicks << CLICK_SHIFT, - high); - if (r != 0) - printf("do_x86_vm: sys_vm_setbuf failed: %d\n", r); } /*=========================================================================* @@ -625,8 +481,14 @@ PRIVATE void send_work() /* Ask the kernel to deliver the signal */ r= sys_sigsend(rmp->mp_endpoint, &rmp->mp_sigmsg); - if (r != OK) + if (r != OK) { +#if 0 panic(__FILE__,"sys_sigsend failed",r); +#else + printf("PM: PM_UNPAUSE: sys_sigsend failed to %d: %d\n", + rmp->mp_endpoint, r); +#endif + } break; @@ -674,7 +536,9 @@ PRIVATE void send_work() case PM_DUMPCORE: m.m_type= call; m.PM_CORE_PROC= rmp->mp_endpoint; + /* XXX m.PM_CORE_SEGPTR= (char *)rmp->mp_seg; + */ /* Mark the process as busy */ rmp->mp_fs_call= PM_BUSY; @@ -715,9 +579,8 @@ PRIVATE void send_work() PRIVATE void handle_fs_reply(m_ptr) message *m_ptr; { - int r, proc_e, proc_n; + int r, proc_e, proc_n, s; struct mproc *rmp; - phys_clicks base, size; switch(m_ptr->m_type) { @@ -746,30 +609,8 @@ message *m_ptr; } /* Release the memory occupied by the child. */ - if (find_share(rmp, rmp->mp_ino, rmp->mp_dev, - rmp->mp_ctime) == NULL) { - /* No other process shares the text segment, - * so free it. - */ - free_mem(rmp->mp_seg[T].mem_phys, - rmp->mp_seg[T].mem_len); - } - - base= rmp->mp_seg[D].mem_phys; - size= rmp->mp_seg[S].mem_vir + rmp->mp_seg[S].mem_len - - rmp->mp_seg[D].mem_vir; - - if (rmp->mp_flags & HAS_DMA) - { - /* Delay freeing the memory segmented until the - * DMA buffers have been released. - */ - release_dma(rmp->mp_endpoint, base, size); - } - else - { - /* Free the data and stack segments. */ - free_mem(base, size); + if((s=vm_exit(rmp->mp_endpoint)) != OK) { + panic(__FILE__, "vm_exit() failed", s); } if (m_ptr->m_type == PM_EXIT_REPLY_TR && @@ -883,30 +724,8 @@ message *m_ptr; } /* Release the memory occupied by the child. */ - if (find_share(rmp, rmp->mp_ino, rmp->mp_dev, - rmp->mp_ctime) == NULL) { - /* No other process shares the text segment, - * so free it. - */ - free_mem(rmp->mp_seg[T].mem_phys, - rmp->mp_seg[T].mem_len); - } - - base= rmp->mp_seg[D].mem_phys; - size= rmp->mp_seg[S].mem_vir + rmp->mp_seg[S].mem_len - - rmp->mp_seg[D].mem_vir; - - if (rmp->mp_flags & HAS_DMA) - { - /* Delay freeing the memory segmented until the - * DMA buffers have been released. - */ - release_dma(rmp->mp_endpoint, base, size); - } - else - { - /* Free the data and stack segments. */ - free_mem(base, size); + if((s=vm_exit(rmp->mp_endpoint)) != OK) { + panic(__FILE__, "vm_exit() failed", s); } /* Clean up if the parent has collected the exit diff --git a/servers/pm/misc.c b/servers/pm/misc.c index d27d70270..5508d8014 100644 --- a/servers/pm/misc.c +++ b/servers/pm/misc.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -66,24 +67,13 @@ PUBLIC unsigned long calls_stats[NCALLS]; *===========================================================================*/ PUBLIC int do_allocmem() { - vir_clicks mem_clicks; - phys_clicks mem_base; - - /* This call is dangerous. Memory will be lost of the requesting process - * forgets about it. - */ - if (mp->mp_effuid != 0) - { - printf("PM: unauthorized call of do_allocmem by proc %d\n", - mp->mp_endpoint); - return EPERM; - } - - mem_clicks = (m_in.memsize + CLICK_SIZE -1 ) >> CLICK_SHIFT; - mem_base = alloc_mem(mem_clicks); - if (mem_base == NO_MEM) return(ENOMEM); - mp->mp_reply.membase = (phys_bytes) (mem_base << CLICK_SHIFT); - return(OK); + int r; + phys_bytes retmembase; + r = vm_allocmem(m_in.memsize, &retmembase); + if(r == OK) + mp->mp_reply.membase = retmembase; + printf("PM: do_allocmem: %d\n", r); + return r; } /*===========================================================================* @@ -91,6 +81,9 @@ PUBLIC int do_allocmem() *===========================================================================*/ PUBLIC int do_freemem() { +#if 1 + return ENOSYS; +#else vir_clicks mem_clicks; phys_clicks mem_base; @@ -108,6 +101,7 @@ PUBLIC int do_freemem() mem_base = (m_in.membase + CLICK_SIZE -1 ) >> CLICK_SHIFT; free_mem(mem_base, mem_clicks); return(OK); +#endif } /*===========================================================================* @@ -215,9 +209,7 @@ PUBLIC int do_getsysinfo() struct loadinfo loadinfo; static struct proc proctab[NR_PROCS+NR_TASKS]; size_t len; - static struct pm_mem_info pmi; int s, r; - size_t holesize; /* This call leaks important information (the contents of registers). * harmless data (such as the load should get their own calls) @@ -251,14 +243,6 @@ PUBLIC int do_getsysinfo() src_addr = (vir_bytes) proctab; len = sizeof(proctab); break; - case SI_MEM_ALLOC: - holesize = sizeof(pmi.pmi_holes); - if((r=mem_holes_copy(pmi.pmi_holes, &holesize, - &pmi.pmi_hi_watermark)) != OK) - return r; - src_addr = (vir_bytes) &pmi; - len = sizeof(pmi); - break; case SI_LOADINFO: /* loadinfo is obtained via PM */ sys_getloadinfo(&loadinfo); src_addr = (vir_bytes) &loadinfo; @@ -329,12 +313,18 @@ PUBLIC int do_getprocnr() return EPERM; } - printf("PM: do_getprocnr call from endpoint %d\n", mp->mp_endpoint); +#if 0 + printf("PM: do_getprocnr(%d) call from endpoint %d, %s\n", + m_in.pid, mp->mp_endpoint, mp->mp_name); +#endif if (m_in.pid >= 0) { /* lookup process by pid */ for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) { if ((rmp->mp_flags & IN_USE) && (rmp->mp_pid==m_in.pid)) { mp->mp_reply.endpt = rmp->mp_endpoint; +#if 0 + printf("PM: pid result: %d\n", rmp->mp_endpoint); +#endif return(OK); } } @@ -349,11 +339,17 @@ PUBLIC int do_getprocnr() if (((rmp->mp_flags & (IN_USE | ZOMBIE)) == IN_USE) && strncmp(rmp->mp_name, search_key, key_len)==0) { mp->mp_reply.endpt = rmp->mp_endpoint; + printf("PM: name %s result: %d\n", search_key, + rmp->mp_endpoint); return(OK); } } + printf("PM: name %s result: ESRCH\n", search_key); return(ESRCH); } else { /* return own/parent process number */ +#if 0 + printf("PM: endpt result: %d\n", mp->mp_reply.endpt); +#endif mp->mp_reply.endpt = who_e; mp->mp_reply.pendpt = mproc[mp->mp_parent].mp_endpoint; } @@ -526,7 +522,7 @@ PUBLIC int do_svrctl() return s; if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.val, SELF, (vir_bytes) local_param_overrides[local_params].value, - sysgetenv.keylen)) != OK) + sysgetenv.vallen)) != OK) return s; local_param_overrides[local_params].name[sysgetenv.keylen] = '\0'; local_param_overrides[local_params].value[sysgetenv.vallen] = '\0'; @@ -576,24 +572,6 @@ PUBLIC int do_svrctl() return OK; } -#if ENABLE_SWAP - case MMSWAPON: { - struct mmswapon swapon; - - if (mp->mp_effuid != SUPER_USER) return(EPERM); - - if (sys_datacopy(who_e, (phys_bytes) ptr, - PM_PROC_NR, (phys_bytes) &swapon, - (phys_bytes) sizeof(swapon)) != OK) return(EFAULT); - - return(swap_on(swapon.file, swapon.offset, swapon.size)); } - - case MMSWAPOFF: { - if (mp->mp_effuid != SUPER_USER) return(EPERM); - - return(swap_off()); } -#endif /* SWAP */ - default: return(EINVAL); } @@ -607,8 +585,13 @@ extern char *_brksize; PUBLIC int brk(brk_addr) char *brk_addr; { + int r; /* PM wants to call brk() itself. */ - if(real_brk(&mproc[PM_PROC_NR], (vir_bytes) brk_addr) != OK) { + if((r=vm_brk(PM_PROC_NR, brk_addr)) != OK) { +#if 0 + printf("PM: own brk(%p) failed: vm_brk() returned %d\n", + brk_addr, r); +#endif return -1; } _brksize = brk_addr; diff --git a/servers/pm/mproc.h b/servers/pm/mproc.h index 624e6e6f1..d6110bf6c 100644 --- a/servers/pm/mproc.h +++ b/servers/pm/mproc.h @@ -5,9 +5,9 @@ * of corresponding slots referring to the same process in all three. */ #include +#include EXTERN struct mproc { - struct mem_map mp_seg[NR_LOCAL_SEGS]; /* points to text, data, stack */ char mp_exitstatus; /* storage for status when process exits */ char mp_sigstatus; /* storage for signal # for killed procs */ pid_t mp_pid; /* process id */ @@ -26,11 +26,6 @@ EXTERN struct mproc { gid_t mp_realgid; /* process' real gid */ gid_t mp_effgid; /* process' effective gid */ - /* File identification for sharing. */ - ino_t mp_ino; /* inode number of file */ - dev_t mp_dev; /* device number of file system */ - time_t mp_ctime; /* inode changed time */ - /* Signal handling information. */ sigset_t mp_ignore; /* 1 means ignore the signal, 0 means don't */ sigset_t mp_catch; /* 1 means catch the signal, 0 means don't */ @@ -73,14 +68,10 @@ EXTERN struct mproc { #define ZOMBIE 0x004 /* set by EXIT, cleared by WAIT */ #define PAUSED 0x008 /* set by PAUSE system call */ #define ALARM_ON 0x010 /* set when SIGALRM timer started */ -#define SEPARATE 0x020 /* set if file is separate I & D space */ #define TRACED 0x040 /* set if process is to be traced */ #define STOPPED 0x080 /* set if process stopped for tracing */ #define SIGSUSPENDED 0x100 /* set by SIGSUSPEND system call */ #define REPLY 0x200 /* set if a reply message is pending */ -#define ONSWAP 0x400 /* set if data segment is swapped out */ -#define SWAPIN 0x800 /* set if on the "swap this in" queue */ -#define DONT_SWAP 0x1000 /* never swap out this process */ #define PRIV_PROC 0x2000 /* system process, special privileges */ #define PM_SIG_PENDING 0x4000 /* process got a signal while waiting for FS */ #define PARTIAL_EXEC 0x8000 /* Process got a new map but no content */ diff --git a/servers/pm/profile.c b/servers/pm/profile.c index 585303991..b63d48b50 100644 --- a/servers/pm/profile.c +++ b/servers/pm/profile.c @@ -97,13 +97,13 @@ int info_size; /* Check if supplied pointers point into user process. */ if ((r = sys_umap(who_e, D, (vir_bytes) m_in.PROF_CTL_PTR, - info_size, &p)) != OK) { + 1, &p)) != OK) { printf("PM: PROFILE: umap failed for process %d\n", who_e); return r; } if ((r =sys_umap(who_e, D, (vir_bytes) m_in.PROF_MEM_PTR, - m_in.PROF_MEM_SIZE, &p)) != OK) { + 1, &p)) != OK) { printf("PM: PROFILE: umap failed for process %d\n", who_e); return r; } diff --git a/servers/pm/proto.h b/servers/pm/proto.h index ac8919efb..ef6e6045e 100644 --- a/servers/pm/proto.h +++ b/servers/pm/proto.h @@ -7,40 +7,19 @@ struct memory; #include -/* alloc.c */ -_PROTOTYPE( phys_clicks alloc_mem, (phys_clicks clicks) ); -_PROTOTYPE( void free_mem, (phys_clicks base, phys_clicks clicks) ); -_PROTOTYPE( void mem_init, (struct memory *chunks, phys_clicks *free) ); +/* break.c */ +_PROTOTYPE( int do_brk, (void) ); + +/* devio.c */ +_PROTOTYPE( int do_dev_io, (void) ); +_PROTOTYPE( int do_dev_io, (void) ); + +/* dma.c */ _PROTOTYPE( int do_adddma, (void) ); _PROTOTYPE( int do_deldma, (void) ); _PROTOTYPE( int do_getdma, (void) ); _PROTOTYPE( void release_dma, (endpoint_t proc_e, phys_clicks base, phys_clicks size) ); -#if ENABLE_SWAP -_PROTOTYPE( int swap_on, (char *file, u32_t offset, u32_t size) ); -_PROTOTYPE( int swap_off, (void) ); -_PROTOTYPE( void swap_in, (void) ); -_PROTOTYPE( void swap_inqueue, (struct mproc *rmp) ); -#else /* !SWAP */ -#define swap_in() ((void)0) -#define swap_inqueue(rmp) ((void)0) -#endif /* !SWAP */ -_PROTOTYPE(int mem_holes_copy, (struct hole *, size_t *, u32_t *) ); - -/* asynsend.c */ -_PROTOTYPE( int asynsend, (endpoint_t dst, message *mp) ); - -/* break.c */ -_PROTOTYPE( int adjust, (struct mproc *rmp, - vir_clicks data_clicks, vir_bytes sp) ); -_PROTOTYPE( int do_brk, (void) ); -_PROTOTYPE( int real_brk, (struct mproc *pr, vir_bytes v) ); -_PROTOTYPE( int size_ok, (int file_type, vir_clicks tc, vir_clicks dc, - vir_clicks sc, vir_clicks dvir, vir_clicks s_vir) ); - -/* devio.c */ -_PROTOTYPE( int do_dev_io, (void) ); -_PROTOTYPE( int do_dev_io, (void) ); /* dmp.c */ _PROTOTYPE( int do_fkey_pressed, (void) ); @@ -50,8 +29,6 @@ _PROTOTYPE( int do_exec, (void) ); _PROTOTYPE( int exec_newmem, (void) ); _PROTOTYPE( int do_execrestart, (void) ); _PROTOTYPE( void exec_restart, (struct mproc *rmp, int result) ); -_PROTOTYPE( struct mproc *find_share, (struct mproc *mp_ign, Ino_t ino, - Dev_t dev, time_t ctime) ); /* forkexit.c */ _PROTOTYPE( int do_fork, (void) ); @@ -131,8 +108,6 @@ _PROTOTYPE( void stop_proc, (struct mproc *rmp, int sig_nr) ); _PROTOTYPE( pid_t get_free_pid, (void) ); _PROTOTYPE( int no_sys, (void) ); _PROTOTYPE( void panic, (char *who, char *mess, int num) ); -_PROTOTYPE( int get_stack_ptr, (int proc_nr, vir_bytes *sp) ); -_PROTOTYPE( int get_mem_map, (int proc_nr, struct mem_map *mem_map) ); _PROTOTYPE( char *find_param, (const char *key)); _PROTOTYPE( int proc_from_pid, (pid_t p)); _PROTOTYPE( int pm_isokendpt, (int ep, int *proc)); diff --git a/servers/pm/signal.c b/servers/pm/signal.c index def9e093d..db3f288ad 100644 --- a/servers/pm/signal.c +++ b/servers/pm/signal.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -251,11 +252,15 @@ sigset_t sig_map; int i, proc_nr; pid_t proc_id, id; - if(pm_isokendpt(proc_nr_e, &proc_nr) != OK || proc_nr < 0) + if(pm_isokendpt(proc_nr_e, &proc_nr) != OK || proc_nr < 0) { + printf("PM: handle_ksig: %d?? not ok\n", proc_nr_e); return; + } rmp = &mproc[proc_nr]; - if ((rmp->mp_flags & (IN_USE | ZOMBIE)) != IN_USE) + if ((rmp->mp_flags & (IN_USE | ZOMBIE)) != IN_USE) { + printf("PM: handle_ksig: %d?? zombie / not in use\n", proc_nr_e); return; +} proc_id = rmp->mp_pid; mp = &mproc[0]; /* pretend signals are from PM */ mp->mp_procgrp = rmp->mp_procgrp; /* get process group right */ @@ -269,6 +274,10 @@ sigset_t sig_map; */ for (i = 1; i <= _NSIG; i++) { if (!sigismember(&sig_map, i)) continue; +#if 0 + printf("PM: sig %d for %d from kernel\n", + i, proc_nr_e); +#endif switch (i) { case SIGINT: case SIGQUIT: @@ -409,7 +418,7 @@ int signo; /* signal to send to process (1 to _NSIG) */ * If there is insufficient stack space, kill the process. */ - vir_bytes new_sp; + vir_bytes cur_sp; int s; int slot; int sigflags; @@ -444,18 +453,8 @@ int signo; /* signal to send to process (1 to _NSIG) */ sigaddset(&rmp->mp_sigpending, signo); return; } -#if ENABLE_SWAP - if (rmp->mp_flags & ONSWAP) { - /* Process is swapped out, leave signal pending. */ - sigaddset(&rmp->mp_sigpending, signo); - swap_inqueue(rmp); - return; - } -#endif sigflags = rmp->mp_sigact[signo].sa_flags; if (sigismember(&rmp->mp_catch, signo)) { - /* Stop process from running before we do stack calculations. */ - sys_nice(rmp->mp_endpoint, PRIO_STOP); if (rmp->mp_flags & SIGSUSPENDED) rmp->mp_sigmsg.sm_mask = rmp->mp_sigmask2; else @@ -464,18 +463,8 @@ int signo; /* signal to send to process (1 to _NSIG) */ rmp->mp_sigmsg.sm_sighandler = (vir_bytes) rmp->mp_sigact[signo].sa_handler; rmp->mp_sigmsg.sm_sigreturn = rmp->mp_sigreturn; - if ((s=get_stack_ptr(rmp->mp_endpoint, &new_sp)) != OK) - panic(__FILE__,"couldn't get new stack pointer (for sig)",s); - rmp->mp_sigmsg.sm_stkptr = new_sp; - - /* Make room for the sigcontext and sigframe struct. */ - new_sp -= sizeof(struct sigcontext) - + 3 * sizeof(char *) + 2 * sizeof(int); - - if (adjust(rmp, rmp->mp_seg[D].mem_len, new_sp) != OK) - goto doterminate; - rmp->mp_sigmask |= rmp->mp_sigact[signo].sa_mask; + if (sigflags & SA_NODEFER) sigdelset(&rmp->mp_sigmask, signo); else @@ -487,6 +476,13 @@ int signo; /* signal to send to process (1 to _NSIG) */ } sigdelset(&rmp->mp_sigpending, signo); + /* Stop process from running before we fiddle with its stack. */ + sys_nice(rmp->mp_endpoint, PRIO_STOP); + if(vm_push_sig(rmp->mp_endpoint, &cur_sp) != OK) + goto doterminate; + + rmp->mp_sigmsg.sm_stkptr = cur_sp; + /* Check to see if process is hanging on a PAUSE, WAIT or SIGSUSPEND * call. */ @@ -519,22 +515,24 @@ int signo; /* signal to send to process (1 to _NSIG) */ doterminate: /* Signal should not or cannot be caught. Take default action. */ - if (sigismember(&ign_sset, signo)) return; + if (sigismember(&ign_sset, signo)) { + return; +} + + /* This process will exit, with or without dumping core. + * Announce this fact to VM. + */ + if((s=vm_willexit(rmp->mp_endpoint)) != OK) { + panic(__FILE__,"sig_proc: vm_willexit failed", s); + } rmp->mp_sigstatus = (char) signo; if (sigismember(&core_sset, signo) && slot != FS_PROC_NR) { -#if ENABLE_SWAP - if (rmp->mp_flags & ONSWAP) { - /* Process is swapped out, leave signal pending. */ - sigaddset(&rmp->mp_sigpending, signo); - swap_inqueue(rmp); + printf("PM: signal %d for %d / %s\n", signo, rmp->mp_pid, rmp->mp_name); + s= dump_core(rmp); + if (s == SUSPEND) { return; } -#endif - - s= dump_core(rmp); - if (s == SUSPEND) - return; /* Not dumping core, just call exit */ } @@ -689,13 +687,13 @@ register struct mproc *rmp; /* whose core is to be dumped */ int r, proc_nr, proc_nr_e, parent_waiting; pid_t procgrp; +#if 0 vir_bytes current_sp; +#endif struct mproc *p_mp; clock_t user_time, sys_time; -#if 0 printf("dumpcore for %d / %s\n", rmp->mp_pid, rmp->mp_name); -#endif /* Do not create core files for set uid execution */ if (rmp->mp_realuid != rmp->mp_effuid) return OK; @@ -706,9 +704,11 @@ register struct mproc *rmp; /* whose core is to be dumped */ * the adjust() for sending a signal to fail due to safety checking. * Maybe make SAFETY_BYTES a parameter. */ +#if 0 if ((r= get_stack_ptr(rmp->mp_endpoint, ¤t_sp)) != OK) panic(__FILE__,"couldn't get new stack pointer (for core)", r); adjust(rmp, rmp->mp_seg[D].mem_len, current_sp); +#endif /* Tell FS about the exiting process. */ if (rmp->mp_fs_call != PM_IDLE) @@ -732,7 +732,7 @@ register struct mproc *rmp; /* whose core is to be dumped */ /* Do accounting: fetch usage times and accumulate at parent. */ if((r=sys_times(proc_nr_e, &user_time, &sys_time, NULL)) != OK) - panic(__FILE__,"pm_exit: sys_times failed", r); + panic(__FILE__,"dump_core: sys_times failed", r); p_mp = &mproc[rmp->mp_parent]; /* process' parent */ p_mp->mp_child_utime += user_time + rmp->mp_child_utime; /* add user time */ @@ -752,7 +752,7 @@ register struct mproc *rmp; /* whose core is to be dumped */ { /* destroy system processes without waiting for FS */ if((r= sys_exit(rmp->mp_endpoint)) != OK) - panic(__FILE__, "pm_exit: sys_exit failed", r); + panic(__FILE__, "dump_core: sys_exit failed", r); /* Just send a SIGCHLD. Dealing with waidpid is too complicated * here. diff --git a/servers/pm/trace.c b/servers/pm/trace.c index 261809735..943169602 100644 --- a/servers/pm/trace.c +++ b/servers/pm/trace.c @@ -69,6 +69,7 @@ PUBLIC int do_trace() if ((child=find_proc(m_in.pid))==NIL_MPROC) return(ESRCH); +#if 0 /* Should check for shared text */ /* Make sure the text segment is not used as a source for shared @@ -77,6 +78,7 @@ PUBLIC int do_trace() child->mp_ino= 0; child->mp_dev= 0; child->mp_ctime= 0; +#endif r= sys_trace(m_in.request,child->mp_endpoint,m_in.taddr,&m_in.data); if (r != OK) return(r); diff --git a/servers/pm/utility.c b/servers/pm/utility.c index 23adbdcfe..405c7fdc8 100644 --- a/servers/pm/utility.c +++ b/servers/pm/utility.c @@ -6,7 +6,6 @@ * allowed: see if an access is permitted * no_sys: called for invalid system call numbers * panic: PM has run aground of a fatal error - * get_mem_map: get memory map of given process * get_stack_ptr: get stack pointer of given process * proc_from_pid: return process pointer from pid number */ @@ -105,38 +104,6 @@ const char *name; return(NULL); } -/*===========================================================================* - * get_mem_map * - *===========================================================================*/ -PUBLIC int get_mem_map(proc_nr, mem_map) -int proc_nr; /* process to get map of */ -struct mem_map *mem_map; /* put memory map here */ -{ - struct proc p; - int s; - - if ((s=sys_getproc(&p, proc_nr)) != OK) - return(s); - memcpy(mem_map, p.p_memmap, sizeof(p.p_memmap)); - return(OK); -} - -/*===========================================================================* - * get_stack_ptr * - *===========================================================================*/ -PUBLIC int get_stack_ptr(proc_nr_e, sp) -int proc_nr_e; /* process to get sp of */ -vir_bytes *sp; /* put stack pointer here */ -{ - struct proc p; - int s; - - if ((s=sys_getproc(&p, proc_nr_e)) != OK) - return(s); - *sp = p.p_reg.sp; - return(OK); -} - /*===========================================================================* * proc_from_pid * *===========================================================================*/ diff --git a/servers/rs/Makefile b/servers/rs/Makefile index 94f466551..5bccbacc4 100644 --- a/servers/rs/Makefile +++ b/servers/rs/Makefile @@ -16,7 +16,7 @@ CC = exec cc CPPFLAGS = -I../../kernel/arch/$(ARCH)/include CFLAGS = -I$i $(CPROFILE) $(CPPFLAGS) LDFLAGS = -i -LIBS = -lsys -lsysutil +LIBS = -lsys UTIL_OBJ = service.o OBJ = exec.o main.o manager.o diff --git a/servers/rs/exec.c b/servers/rs/exec.c index 9f02d96ec..d7ce23256 100644 --- a/servers/rs/exec.c +++ b/servers/rs/exec.c @@ -171,7 +171,11 @@ static void do_exec(int proc_e, char *exec, size_t exec_len, char *progname, patch_ptr(frame, vsp); r = sys_datacopy(SELF, (vir_bytes) frame, proc_e, (vir_bytes) vsp, (phys_bytes)frame_len); - if (r != OK) panic(__FILE__,"pm_exec stack copy err on", proc_e); + if (r != OK) { + printf("RS: stack_top is 0x%lx; tried to copy to 0x%lx in %d\n", + stack_top, vsp); + panic("RS", "do_exec: stack copy err on", proc_e); + } off = hdrlen; @@ -261,8 +265,8 @@ int *allow_setuidp; *load_textp= !!(m.m1_i2 & EXC_NM_RF_LOAD_TEXT); *allow_setuidp= !!(m.m1_i2 & EXC_NM_RF_ALLOW_SETUID); #if 0 - printf("exec_newmem: stack_top = 0x%x\n", *stack_topp); - printf("exec_newmem: load_text = %d\n", *load_textp); + printf("RS: exec_newmem: stack_top = 0x%x\n", *stack_topp); + printf("RS: exec_newmem: load_text = %d\n", *load_textp); #endif return m.m_type; } diff --git a/servers/rs/manager.c b/servers/rs/manager.c index 0b7495734..fb6b03b85 100644 --- a/servers/rs/manager.c +++ b/servers/rs/manager.c @@ -309,10 +309,12 @@ message *m_ptr; /* request message pointer */ rp->r_priv.s_io_tab[i].ior_base= rs_start.rss_io[i].base; rp->r_priv.s_io_tab[i].ior_limit= rs_start.rss_io[i].base+rs_start.rss_io[i].len-1; +#if 0 if(rs_verbose) printf("RS: do_start: I/O [%x..%x]\n", rp->r_priv.s_io_tab[i].ior_base, rp->r_priv.s_io_tab[i].ior_limit); +#endif } if (rs_start.rss_nr_pci_id > MAX_NR_PCI_ID) @@ -532,12 +534,18 @@ PUBLIC void do_exit(message *m_ptr) while ( (exit_pid = waitpid(-1, &exit_status, WNOHANG)) != 0 ) { if(rs_verbose) { +#if 0 printf("RS: pid %d, ", exit_pid); +#endif if (WIFSIGNALED(exit_status)) { +#if 0 printf("killed, signal number %d\n", WTERMSIG(exit_status)); +#endif } else if (WIFEXITED(exit_status)) { +#if 0 printf("normal exit, status %d\n", WEXITSTATUS(exit_status)); +#endif } } @@ -649,7 +657,7 @@ rp->r_restarts= 0; break; } } - } + } } /*===========================================================================* @@ -748,11 +756,15 @@ endpoint_t *endpoint; use_copy= (rp->r_exec != NULL); + /* Now fork and branch for parent and child process (and check for error). */ - if (use_copy) + if (use_copy) { + if(rs_verbose) printf("RS: fork_nb..\n"); child_pid= fork_nb(); - else + } else { + if(rs_verbose) printf("RS: fork regular..\n"); child_pid = fork(); + } switch(child_pid) { /* see fork(2) */ case -1: /* fork failed */ @@ -783,7 +795,13 @@ endpoint_t *endpoint; exit(1); /* terminate child */ default: /* parent process */ +#if 0 + if(rs_verbose) printf("RS: parent forked, pid %d..\n", child_pid); +#endif child_proc_nr_e = getnprocnr(child_pid); /* get child slot */ +#if 0 + if(rs_verbose) printf("RS: forked into %d..\n", child_proc_nr_e); +#endif break; /* continue below */ } @@ -817,7 +835,10 @@ endpoint_t *endpoint; s= ds_publish_u32(rp->r_label, child_proc_nr_e); if (s != OK) - printf("start_service: ds_publish_u32 failed: %d\n", s); + printf("RS: start_service: ds_publish_u32 failed: %d\n", s); + else if(rs_verbose) + printf("RS: start_service: ds_publish_u32 done: %s -> %d\n", + rp->r_label, child_proc_nr_e); if (rp->r_dev_nr > 0) { /* set driver map */ if ((s=mapdriver5(rp->r_label, strlen(rp->r_label), @@ -1054,8 +1075,10 @@ struct priv *privp; if (!(rp->r_call_mask[src_word] & mask)) continue; call_nr= src_word*src_bits_per_word+src_bit; +#if 0 if(rs_verbose) printf("RS: init_privs: system call %d\n", call_nr); +#endif dst_word= call_nr / dst_bits_per_word; mask= (1UL << (call_nr % dst_bits_per_word)); if (dst_word >= CALL_MASK_SIZE) diff --git a/servers/rs/service.c b/servers/rs/service.c index 71d355490..0a173f985 100644 --- a/servers/rs/service.c +++ b/servers/rs/service.c @@ -680,8 +680,8 @@ struct { "VSAFECOPY", SYS_VSAFECOPY }, { "SETGRANT", SYS_SETGRANT }, { "READBIOS", SYS_READBIOS }, - { "VM_MAP", SYS_VM_MAP }, { "MAPDMA", SYS_MAPDMA }, + { "VMCTL", SYS_VMCTL }, { NULL, 0 } }; @@ -725,7 +725,9 @@ PRIVATE void do_ipc(config_t *cpe) strcat(list, " "); strcat(list, cpe->word); } +#if 0 printf("do_ipc: got list '%s'\n", list); +#endif if (req_ipc) fatal("do_ipc: req_ipc is set"); diff --git a/servers/vfs/Makefile b/servers/vfs/Makefile index f69576458..ebee1bd80 100644 --- a/servers/vfs/Makefile +++ b/servers/vfs/Makefile @@ -11,13 +11,13 @@ h = $i/minix CC = exec cc CFLAGS = -I$i $(EXTRA_OPTS) $(CPROFILE) LDFLAGS = -i -LIBS = -lsysutil -lsys -ltimers +LIBS = -lsys -ltimers OBJ = main.o open.o read.o write.o pipe.o dmap.o \ path.o device.o mount.o link.o exec.o \ filedes.o stadir.o protect.o time.o \ lock.o misc.o utility.o select.o timers.o table.o \ - vnode.o vmnt.o request.o kputc.o + vnode.o vmnt.o request.o kputc.o mmap.o # build local binary install all build: $(SERVER) diff --git a/servers/vfs/buf.h b/servers/vfs/buf.h deleted file mode 100644 index a17513683..000000000 --- a/servers/vfs/buf.h +++ /dev/null @@ -1,75 +0,0 @@ -/* Buffer (block) cache. To acquire a block, a routine calls get_block(), - * telling which block it wants. The block is then regarded as "in use" - * and has its 'b_count' field incremented. All the blocks that are not - * in use are chained together in an LRU list, with 'front' pointing - * to the least recently used block, and 'rear' to the most recently used - * block. A reverse chain, using the field b_prev is also maintained. - * Usage for LRU is measured by the time the put_block() is done. The second - * parameter to put_block() can violate the LRU order and put a block on the - * front of the list, if it will probably not be needed soon. If a block - * is modified, the modifying routine must set b_dirt to DIRTY, so the block - * will eventually be rewritten to the disk. - */ - -#include /* need struct direct */ -#include - -EXTERN struct buf { - /* Data portion of the buffer. */ - union { - char b__data[_MAX_BLOCK_SIZE]; /* ordinary user data */ -/* directory block */ - struct direct b__dir[NR_DIR_ENTRIES(_MAX_BLOCK_SIZE)]; -/* V1 indirect block */ - zone1_t b__v1_ind[V1_INDIRECTS]; -/* V2 indirect block */ - zone_t b__v2_ind[V2_INDIRECTS(_MAX_BLOCK_SIZE)]; -/* V1 inode block */ - d1_inode b__v1_ino[V1_INODES_PER_BLOCK]; -/* V2 inode block */ - d2_inode b__v2_ino[V2_INODES_PER_BLOCK(_MAX_BLOCK_SIZE)]; -/* bit map block */ - bitchunk_t b__bitmap[FS_BITMAP_CHUNKS(_MAX_BLOCK_SIZE)]; - } b; - - /* Header portion of the buffer. */ - struct buf *b_next; /* used to link all free bufs in a chain */ - struct buf *b_prev; /* used to link all free bufs the other way */ - struct buf *b_hash; /* used to link bufs on hash chains */ - block_t b_blocknr; /* block number of its (minor) device */ - dev_t b_dev; /* major | minor device where block resides */ - char b_dirt; /* CLEAN or DIRTY */ - char b_count; /* number of users of this buffer */ -} buf[NR_BUFS]; - -/* A block is free if b_dev == NO_DEV. */ - -#define NIL_BUF ((struct buf *) 0) /* indicates absence of a buffer */ - -/* These defs make it possible to use to bp->b_data instead of bp->b.b__data */ -#define b_data b.b__data -#define b_dir b.b__dir -#define b_v1_ind b.b__v1_ind -#define b_v2_ind b.b__v2_ind -#define b_v1_ino b.b__v1_ino -#define b_v2_ino b.b__v2_ino -#define b_bitmap b.b__bitmap - -EXTERN struct buf *buf_hash[NR_BUF_HASH]; /* the buffer hash table */ - -EXTERN struct buf *front; /* points to least recently used free block */ -EXTERN struct buf *rear; /* points to most recently used free block */ -EXTERN int bufs_in_use; /* # bufs currently in use (not on free list)*/ - -/* When a block is released, the type of usage is passed to put_block(). */ -#define WRITE_IMMED 0100 /* block should be written to disk now */ -#define ONE_SHOT 0200 /* set if block not likely to be needed soon */ - -#define INODE_BLOCK 0 /* inode block */ -#define DIRECTORY_BLOCK 1 /* directory block */ -#define INDIRECT_BLOCK 2 /* pointer block */ -#define MAP_BLOCK 3 /* bit map */ -#define FULL_DATA_BLOCK 5 /* data, fully used */ -#define PARTIAL_DATA_BLOCK 6 /* data, partly used*/ - -#define HASH_MASK (NR_BUF_HASH - 1) /* mask for hashing block numbers */ diff --git a/servers/vfs/device.c b/servers/vfs/device.c index 58ceabbe5..14719ec81 100644 --- a/servers/vfs/device.c +++ b/servers/vfs/device.c @@ -633,6 +633,10 @@ message *mess_ptr; /* pointer to message for task */ int r, proc_e; + if(task_nr == SYSTEM) { + printf("VFS: sending %d to SYSTEM\n", mess_ptr->m_type); + } + proc_e = mess_ptr->IO_ENDPT; r = sendrec(task_nr, mess_ptr); @@ -1117,6 +1121,7 @@ PUBLIC void reopen_reply() restart_reopen(maj); } +#if 0 #define ASYN_NR 100 PRIVATE asynmsg_t msgtable[ASYN_NR]; PRIVATE int first_slot= 0, next_slot= 0; @@ -1203,4 +1208,5 @@ message *mp; /* Tell the kernel to rescan the table */ return senda(msgtable+first_slot, next_slot-first_slot); } +#endif diff --git a/servers/vfs/exec.c b/servers/vfs/exec.c index f86c10129..e55da6bbd 100644 --- a/servers/vfs/exec.c +++ b/servers/vfs/exec.c @@ -221,7 +221,10 @@ printf("return at %s, %d\n", __FILE__, __LINE__); patch_ptr(mbuf, vsp); r = sys_datacopy(SELF, (vir_bytes) mbuf, proc_e, (vir_bytes) vsp, (phys_bytes)frame_len); - if (r != OK) panic(__FILE__,"pm_exec stack copy err on", proc_e); + if (r != OK) { + printf("vfs: datacopy returns %d trying to copy to %p\n", r, vsp); + panic(__FILE__,"pm_exec stack copy err on", proc_e); + } off = hdrlen; @@ -255,7 +258,6 @@ printf("return at %s, %d\n", __FILE__, __LINE__); /* Check if this is a driver that can now be useful. */ dmap_endpt_up(rfp->fp_endpoint); -/*printf("VFSpm_exec: %s OK\n", user_fullpath);*/ return OK; } @@ -432,7 +434,7 @@ vir_bytes *stk_bytes; /* size of initial stack */ unsigned int cum_io_incr; char buf[_MAX_BLOCK_SIZE]; - /* Make user_path the new argv[0]. */ + /* Make user_fullpath the new argv[0]. */ if (!insert_arg(stack, stk_bytes, user_fullpath, REPLACE)) return(ENOMEM); pos = 0; /* Read from the start of the file */ @@ -451,7 +453,7 @@ vir_bytes *stk_bytes; /* size of initial stack */ n -= 2; if (n > PATH_MAX) n = PATH_MAX; - /* Use the user_path variable for temporary storage */ + /* Use the user_fullpath variable for temporary storage */ memcpy(user_fullpath, sp, n); if ((sp = memchr(user_fullpath, '\n', n)) == NULL) /* must be a proper line */ diff --git a/servers/vfs/link.c b/servers/vfs/link.c index 0e901f4b3..e1cbc3047 100644 --- a/servers/vfs/link.c +++ b/servers/vfs/link.c @@ -261,10 +261,13 @@ PUBLIC int do_truncate() PUBLIC int do_ftruncate() { /* As with do_truncate(), truncate_inode() does the actual work. */ + int r; struct filp *rfilp; if ( (rfilp = get_filp(m_in.m2_i1)) == NIL_FILP) return err_code; + if ( (r = forbidden(rfilp->filp_vno, W_BIT, 0 /*!use_realuid*/)) != OK) + return r; return truncate_vn(rfilp->filp_vno, m_in.m2_l1); } diff --git a/servers/vfs/main.c b/servers/vfs/main.c index 52186f77a..9060a7257 100644 --- a/servers/vfs/main.c +++ b/servers/vfs/main.c @@ -1,4 +1,4 @@ -/* 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. * @@ -60,8 +60,6 @@ PUBLIC int main() /* This is the main loop that gets work, processes it, and sends replies. */ while (TRUE) { get_work(); /* sets who and call_nr */ - fp = &fproc[who_p]; /* pointer to proc table struct */ - super_user = (fp->fp_effuid == SU_UID ? TRUE : FALSE); /* su? */ if (who_e == PM_PROC_NR && call_nr != PROC_EVENT) printf("FS: strange, got message %d from PM\n", call_nr); @@ -143,24 +141,60 @@ PUBLIC int main() continue; } - switch(call_nr) - { - case DEVCTL: + /* We only expect notify()s from tasks. */ + if(who_p < 0) { + printf("FS: ignoring message from %d (%d)\n", + who_e, m_in.m_type); + continue; + } + + /* Now it's safe to set and check fp. */ + fp = &fproc[who_p]; /* pointer to proc table struct */ + super_user = (fp->fp_effuid == SU_UID ? TRUE : FALSE); /* su? */ + + /* Calls from VM. */ + if(who_e == VM_PROC_NR) { + int caught = 1; + switch(call_nr) + { + case VM_VFS_OPEN: + error = do_vm_open(); + break; + case VM_VFS_CLOSE: + error = do_vm_close(); + break; + case VM_VFS_MMAP: + error = do_vm_mmap(); + break; + default: + caught = 0; + break; + } + if(caught) { + reply(who_e, error); + continue; + } + } + + /* Other calls. */ + switch(call_nr) + { + case DEVCTL: error= do_devctl(); if (error != SUSPEND) reply(who_e, error); break; - case MAPDRIVER: + case MAPDRIVER: error= do_mapdriver(); if (error != SUSPEND) reply(who_e, error); break; - default: + default: /* Call the internal function that does the work. */ if (call_nr < 0 || call_nr >= NCALLS) { error = SUSPEND; /* Not supposed to happen. */ - printf("FS, warning illegal %d system call by %d\n", + printf("VFS: illegal %d system call by %d\n", call_nr, who_e); } else if (fp->fp_pid == PID_FREE) { error = ENOSYS; @@ -176,7 +210,6 @@ PUBLIC int main() /* Copy the results back to the user and send reply. */ if (error != SUSPEND) { reply(who_e, error); } - } #if 0 if (!check_vrefs()) @@ -336,13 +369,6 @@ PRIVATE void fs_init() * extra block_size requirements are checked at super-block-read-in time. */ if (OPEN_MAX > 127) panic(__FILE__,"OPEN_MAX > 127", NO_NUM); - /* - if (NR_BUFS < 6) panic(__FILE__,"NR_BUFS < 6", NO_NUM); - if (V1_INODE_SIZE != 32) panic(__FILE__,"V1 inode size != 32", NO_NUM); - if (V2_INODE_SIZE != 64) panic(__FILE__,"V2 inode size != 64", NO_NUM); - if (OPEN_MAX > 8 * sizeof(long)) - panic(__FILE__,"Too few bits in fp_cloexec", NO_NUM); - */ /* The following initializations are needed to let dev_opcl succeed .*/ fp = (struct fproc *) NULL; diff --git a/servers/vfs/misc.c b/servers/vfs/misc.c index f1a41b07f..143018f3e 100644 --- a/servers/vfs/misc.c +++ b/servers/vfs/misc.c @@ -219,6 +219,9 @@ PUBLIC int do_fcntl() return EINVAL; } + if ( (r = forbidden(f->filp_vno, W_BIT, 0 /*!use_realuid*/)) != OK) + return r; + /* Copy flock data from userspace. */ if((r = sys_datacopy(who_e, (vir_bytes) m_in.name1, SELF, (vir_bytes) &flock_arg, @@ -369,6 +372,7 @@ int cpid; /* Child process id */ /* Increase the counters in the 'filp' table. */ cp = &fproc[childno]; + fp = &fproc[parentno]; for (i = 0; i < OPEN_MAX; i++) if (cp->fp_filp[i] != NIL_FILP) cp->fp_filp[i]->filp_count++; @@ -379,8 +383,14 @@ int cpid; /* Child process id */ /* A forking process never has an outstanding grant, * as it isn't blocking on i/o. */ - assert(!GRANT_VALID(fp->fp_grant)); - assert(!GRANT_VALID(cp->fp_grant)); + if(GRANT_VALID(fp->fp_grant)) { + printf("vfs: fork: fp (endpoint %d) has grant %d\n", fp->fp_endpoint, fp->fp_grant); + panic(__FILE__, "fp contains valid grant", NO_NUM); + } + if(GRANT_VALID(cp->fp_grant)) { + printf("vfs: fork: cp (endpoint %d) has grant %d\n", cp->fp_endpoint, cp->fp_grant); + panic(__FILE__, "cp contains valid grant", NO_NUM); + } /* A child is not a process leader. */ cp->fp_sesldr = 0; @@ -554,7 +564,9 @@ PUBLIC int do_svrctl() */ if(fproc[proc_nr_n].fp_execced) { /* Reply before calling dev_up */ +#if 0 printf("do_svrctl: replying before dev_up\n"); +#endif reply(who_e, r); dev_up(major); r= SUSPEND; diff --git a/servers/vfs/mmap.c b/servers/vfs/mmap.c new file mode 100644 index 000000000..101ae0dbf --- /dev/null +++ b/servers/vfs/mmap.c @@ -0,0 +1,32 @@ +/* mmap implementation in VFS + * + * The entry points into this file are + * do_vm_mmap: VM calls VM_VFS_MMAP + */ + +#include "fs.h" +#include +#include +#include +#include +#include +#include +#include +#include "file.h" +#include "fproc.h" +#include "lock.h" +#include "param.h" +#include +#include + +#include +#include "vnode.h" +#include "vmnt.h" + +/*===========================================================================* + * do_vm_mmap * + *===========================================================================*/ +PUBLIC int do_vm_mmap() +{ +} + diff --git a/servers/vfs/mount.c b/servers/vfs/mount.c index 193ee40e1..a7135d20a 100644 --- a/servers/vfs/mount.c +++ b/servers/vfs/mount.c @@ -311,8 +311,6 @@ PRIVATE int mount_fs(endpoint_t fs_e) root_node->v_dev = vmp->m_dev; if (replace_root) { - printf("Replacing root\n"); - /* Superblock and root node already read. * Nothing else can go wrong. Perform the mount. */ vmp->m_root_node = root_node; diff --git a/servers/vfs/open.c b/servers/vfs/open.c index d32fb57de..5eb7e3390 100644 --- a/servers/vfs/open.c +++ b/servers/vfs/open.c @@ -795,3 +795,77 @@ PUBLIC void close_reply() } +/*===========================================================================* + * do_vm_open * + *===========================================================================*/ +PUBLIC int do_vm_open() +{ + int len, r, n; + endpoint_t ep; + + len = m_in.VMVO_NAME_LENGTH; + m_out.VMV_ENDPOINT = ep = m_in.VMVO_ENDPOINT; + + /* Do open() call on behalf of any process, performed by VM. */ + if(len < 2 || len > sizeof(user_fullpath)) { + printf("do_vm_open: strange length %d\n", len); + m_out.VMVRO_FD = EINVAL; + return VM_VFS_REPLY_OPEN; + } + + /* Do open on behalf of which process? */ + if(isokendpt(ep, &n) != OK) { + printf("do_vm_open: strange endpoint %d\n", ep); + m_out.VMVRO_FD = EINVAL; + return VM_VFS_REPLY_OPEN; + } + + /* XXX - do open on behalf of this process */ + fp = &fproc[n]; + + /* Get path name from VM address space. */ + if((r=sys_safecopyfrom(VM_PROC_NR, m_in.VMVO_NAME_GRANT, 0, + (vir_bytes) user_fullpath, len, D)) != OK) { + printf("do_vm_open: sys_safecopyfrom failed: %d\n", r); + m_out.VMVRO_FD = EPERM; + return VM_VFS_REPLY_OPEN; + } + + /* Check if path is null-terminated. */ + if(user_fullpath[len-1] != '\0') { + printf("do_vm_open: name (len %d) not 0-terminated\n", len); + m_out.VMVRO_FD = EINVAL; + return VM_VFS_REPLY_OPEN; + } + + /* Perform open(). */ + m_out.VMVRO_FD = common_open(m_in.VMVO_FLAGS, m_in.VMVO_MODE); + m_out.VMV_ENDPOINT = ep; + + /* Send open() reply. */ + return VM_VFS_REPLY_OPEN; +} + +/*===========================================================================* + * do_vm_close * + *===========================================================================*/ +PUBLIC int do_vm_close() +{ + int len, r, n; + endpoint_t ep; + + len = m_in.VMVO_NAME_LENGTH; + + /* Do close() call on behalf of any process, performed by VM. */ + m_out.VMV_ENDPOINT = ep = m_in.VMVC_ENDPOINT; + if(isokendpt(ep, &n) != OK) { + printf("do_vm_close: strange endpoint %d\n", ep); + return VM_VFS_REPLY_CLOSE; + } + + /* Perform close(). */ + r = close_fd(&fproc[n], m_in.VMVC_FD); + + return VM_VFS_REPLY_CLOSE; +} + diff --git a/servers/vfs/pipe.c b/servers/vfs/pipe.c index 407b9d5a5..82ece30f1 100644 --- a/servers/vfs/pipe.c +++ b/servers/vfs/pipe.c @@ -462,7 +462,11 @@ int proc_nr_e; dev_t dev; message mess; - okendpt(proc_nr_e, &proc_nr_p); + if(isokendpt(proc_nr_e, &proc_nr_p) != OK) { + printf("VFS: ignoring unpause for bogus endpoint %d\n", proc_nr_e); + return; + } + rfp = &fproc[proc_nr_p]; if (rfp->fp_suspended == NOT_SUSPENDED) return; diff --git a/servers/vfs/proto.h b/servers/vfs/proto.h index 0812ec0e2..abd92dd55 100644 --- a/servers/vfs/proto.h +++ b/servers/vfs/proto.h @@ -31,7 +31,6 @@ _PROTOTYPE( void dev_up, (int major) ); _PROTOTYPE( endpoint_t suspended_ep, (endpoint_t driver, cp_grant_id_t g) ); _PROTOTYPE( void reopen_reply, (void) ); -_PROTOTYPE( int asynsend, (endpoint_t dst, message *mp) ); /* dmap.c */ _PROTOTYPE( int do_devctl, (void) ); @@ -52,7 +51,7 @@ _PROTOTYPE( int pm_exec, (int proc_e, char *path, vir_bytes path_len, /* filedes.c */ _PROTOTYPE( struct filp *find_filp, (struct vnode *vp, mode_t bits) ); _PROTOTYPE( int get_fd, (int start, mode_t bits, int *k, - struct filp **fpt) ); + struct filp **fpt) ); _PROTOTYPE( struct filp *get_filp, (int fild) ); _PROTOTYPE( struct filp *get_filp2, (struct fproc *rfp, int fild) ); _PROTOTYPE( int inval_filp, (struct filp *) ); @@ -90,6 +89,9 @@ _PROTOTYPE( int do_svrctl, (void) ); _PROTOTYPE( int do_getsysinfo, (void) ); _PROTOTYPE( int pm_dumpcore, (int proc_e, struct mem_map *seg_ptr) ); +/* mmap.c */ +_PROTOTYPE( int do_vm_mmap, (void) ); + /* mount.c */ _PROTOTYPE( int do_fslogin, (void) ); _PROTOTYPE( int do_mount, (void) ); @@ -108,14 +110,16 @@ _PROTOTYPE( int do_mknod, (void) ); _PROTOTYPE( int do_mkdir, (void) ); _PROTOTYPE( int do_open, (void) ); _PROTOTYPE( int do_slink, (void) ); +_PROTOTYPE( int do_vm_open, (void) ); +_PROTOTYPE( int do_vm_close, (void) ); /* path.c */ _PROTOTYPE( int lookup_rel_vp, (struct vnode *start_node, int flags, - int use_realuid, struct vnode **vpp) ); + int use_realuid, struct vnode **vpp) ); _PROTOTYPE( int lookup_vp, (int flags, int use_realuid, - struct vnode **vpp) ); + struct vnode **vpp) ); _PROTOTYPE( int lookup_lastdir_rel, (struct vnode *start_node, - int use_realuid, struct vnode **vpp) ); + int use_realuid, struct vnode **vpp) ); _PROTOTYPE( int lookup_lastdir, (int use_realuid, struct vnode **vpp) ); /* pipe.c */ diff --git a/servers/vfs/utility.c b/servers/vfs/utility.c index d58f7421d..43fbba8b8 100644 --- a/servers/vfs/utility.c +++ b/servers/vfs/utility.c @@ -15,13 +15,12 @@ #include #include #include +#include #include "file.h" #include "fproc.h" #include "param.h" #include "vmnt.h" -PRIVATE int panicking; /* inhibits recursive panics during sync */ - /*===========================================================================* * fetch_name * *===========================================================================*/ @@ -30,7 +29,7 @@ char *path; /* pointer to the path in user space */ int len; /* path length, including 0 byte */ int flag; /* M3 means path may be in message */ { -/* Go get path and put it in 'user_path'. +/* Go get path and put it in 'user_fullpath'. * If 'flag' = M3 and 'len' <= M3_STRING, the path is present in 'message'. * If it is not, go copy it from user space. */ @@ -38,6 +37,8 @@ int flag; /* M3 means path may be in message */ int r; if (len > PATH_MAX) { + printf("VFS: fetch_name: len (%d) > %d\n", len, PATH_MAX); + util_stacktrace(); err_code = ENAMETOOLONG; return(EGENERIC); } @@ -50,11 +51,12 @@ int flag; /* M3 means path may be in message */ if (len <= 0) { err_code = EINVAL; printf("vfs: fetch_name: len %d?\n", len); + util_stacktrace(); return(EGENERIC); } if (flag == M3 && len <= M3_STRING) { - /* Just copy the path from the message to 'user_path'. */ + /* Just copy the path from the message to 'user_fullpath'. */ rpu = &user_fullpath[0]; rpm = m_in.pathname; /* contained in input message */ do { *rpu++ = *rpm++; } while (--len); @@ -88,40 +90,32 @@ PUBLIC int no_sys() return(SUSPEND); } -/*===========================================================================* - * panic * - *===========================================================================*/ -PUBLIC void panic(who, mess, num) -char *who; /* who caused the panic */ -char *mess; /* panic message string */ -int num; /* number to go with it */ -{ - if (!panicking) { /* do not panic during a sync */ - panicking = TRUE; /* prevent another panic during the sync */ - - printf("VFS panic (%s): %s ", who, mess); - if (num != NO_NUM) printf("%d",num); - printf("\n"); - (void) do_sync(); /* flush everything to the disk */ - } else printf("VFS re-panic\n"); - exit(1); -} - /*===========================================================================* * isokendpt_f * *===========================================================================*/ PUBLIC int isokendpt_f(char *file, int line, int endpoint, int *proc, int fatal) { int failed = 0; + endpoint_t ke; *proc = _ENDPOINT_P(endpoint); - if(*proc < 0 || *proc >= NR_PROCS) { + if(endpoint == NONE) { + printf("vfs:%s: endpoint is NONE\n", file, line, endpoint); + failed = 1; + } else if(*proc < 0 || *proc >= NR_PROCS) { printf("vfs:%s:%d: proc (%d) from endpoint (%d) out of range\n", file, line, *proc, endpoint); failed = 1; - } else if(fproc[*proc].fp_endpoint != endpoint) { - printf("vfs:%s:%d: proc (%d) from endpoint (%d) doesn't match " - "known endpoint (%d)\n", - file, line, *proc, endpoint, fproc[*proc].fp_endpoint); + } else if((ke=fproc[*proc].fp_endpoint) != endpoint) { + if(ke == NONE) { + printf("vfs:%s:%d: endpoint (%d) points to NONE slot (%d)\n", + file, line, endpoint, *proc); + assert(fproc[*proc].fp_pid == PID_FREE); + } else { + printf("vfs:%s:%d: proc (%d) from endpoint (%d) doesn't match " + "known endpoint (%d)\n", + file, line, *proc, endpoint, fproc[*proc].fp_endpoint); + assert(fproc[*proc].fp_pid != PID_FREE); + } failed = 1; } diff --git a/servers/vm/Makefile b/servers/vm/Makefile new file mode 100644 index 000000000..29e7e56f4 --- /dev/null +++ b/servers/vm/Makefile @@ -0,0 +1,33 @@ +# Makefile for VM server +SERVER = vm + +include /etc/make.conf + +OBJ = main.o alloc.o utility.o exec.o exit.o fork.o break.o \ + signal.o vfs.o mmap.o slaballoc.o region.o pagefaults.o +ARCHOBJ = $(ARCH)/vm.o $(ARCH)/pagetable.o $(ARCH)/arch_pagefaults.o $(ARCH)/util.o + +CPPFLAGS=-I../../kernel/arch/$(ARCH)/include -I$(ARCH) +CFLAGS = $(CPROFILE) $(CPPFLAGS) + +# build local binary + +all build install: $(SERVER) + #install $(SERVER) + +$(SERVER): $(OBJ) $(ARCHOBJ) + cd $(ARCH) && $(MAKE) + $(CC) -o $@ $(LDFLAGS) $(OBJ) $(ARCHOBJ) -lsys + +# clean up local files +clean: + rm -f $(SERVER) *.o *.bak + cd $(ARCH) && $(MAKE) $@ + +depend: + cd $(ARCH) && $(MAKE) $@ + mkdep "$(CC) -E $(CPPFLAGS)" *.c $(ARCH)/*.c > .depend + +# Include generated dependencies. +include .depend + diff --git a/servers/vm/alloc.c b/servers/vm/alloc.c new file mode 100644 index 000000000..196556e29 --- /dev/null +++ b/servers/vm/alloc.c @@ -0,0 +1,832 @@ +/* This file is concerned with allocating and freeing arbitrary-size blocks of + * physical memory on behalf of the FORK and EXEC system calls. The key data + * structure used is the hole table, which maintains a list of holes in memory. + * It is kept sorted in order of increasing memory address. The addresses + * it contains refers to physical memory, starting at absolute address 0 + * (i.e., they are not relative to the start of PM). During system + * initialization, that part of memory containing the interrupt vectors, + * kernel, and PM are "allocated" to mark them as not available and to + * remove them from the hole list. + * + * The entry points into this file are: + * alloc_mem: allocate a given sized chunk of memory + * free_mem: release a previously allocated chunk of memory + * mem_init: initialize the tables when PM start up + */ + +#define _SYSTEM 1 + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "vm.h" +#include "proto.h" +#include "util.h" +#include "glo.h" + +/* Initially, no free pages are known. */ +PRIVATE phys_bytes free_pages_head = NO_MEM; /* Physical address in bytes. */ + +/* Used for sanity check. */ +PRIVATE phys_bytes mem_low, mem_high; +#define vm_assert_range(addr, len) \ + vm_assert((addr) >= mem_low); \ + vm_assert((addr) + (len) - 1 <= mem_high); + +struct hole { + struct hole *h_next; /* pointer to next entry on the list */ + phys_clicks h_base; /* where does the hole begin? */ + phys_clicks h_len; /* how big is the hole? */ + int freelist; + int holelist; +}; + +#define NIL_HOLE (struct hole *) 0 + +#define _NR_HOLES (_NR_PROCS*2) /* No. of memory holes maintained by VM */ + +PRIVATE struct hole hole[_NR_HOLES]; + +PRIVATE struct hole *hole_head; /* pointer to first hole */ +PRIVATE struct hole *free_slots;/* ptr to list of unused table slots */ + +FORWARD _PROTOTYPE( void del_slot, (struct hole *prev_ptr, struct hole *hp) ); +FORWARD _PROTOTYPE( void merge, (struct hole *hp) ); +FORWARD _PROTOTYPE( void free_pages, (phys_bytes addr, int pages) ); +FORWARD _PROTOTYPE( phys_bytes alloc_pages, (int pages, int flags) ); + +#if SANITYCHECKS +FORWARD _PROTOTYPE( void holes_sanity_f, (char *fn, int line) ); +#define CHECKHOLES holes_sanity_f(__FILE__, __LINE__) +#else +#define CHECKHOLES +#endif + +/* Sanity check for parameters of node p. */ +#define vm_assert_params(p, bytes, next) { \ + vm_assert((p) != NO_MEM); \ + vm_assert(!((bytes) % VM_PAGE_SIZE)); \ + vm_assert(!((next) % VM_PAGE_SIZE)); \ + vm_assert((bytes) > 0); \ + vm_assert((p) + (bytes) > (p)); \ + vm_assert((next) == NO_MEM || ((p) + (bytes) <= (next))); \ + vm_assert_range((p), (bytes)); \ + vm_assert_range((next), 1); \ +} + +/* Retrieve size of free block and pointer to next block from physical + * address (page) p. + */ +#define GET_PARAMS(p, bytes, next) { \ + phys_readaddr((p), &(bytes), &(next)); \ + vm_assert_params((p), (bytes), (next)); \ +} + +/* Write parameters to physical page p. */ +#define SET_PARAMS(p, bytes, next) { \ + vm_assert_params((p), (bytes), (next)); \ + phys_writeaddr((p), (bytes), (next)); \ +} + + +void availbytes(vir_bytes *bytes, vir_bytes *chunks) +{ + phys_bytes p, nextp; + *bytes = 0; + *chunks = 0; + for(p = free_pages_head; p != NO_MEM; p = nextp) { + phys_bytes thissize, ret; + GET_PARAMS(p, thissize, nextp); + (*bytes) += thissize; + (*chunks)++; + if(nextp != NO_MEM) { + vm_assert(nextp > p); + vm_assert(nextp > p + thissize); + } + } + + return; +} + + +#if SANITYCHECKS + +/*===========================================================================* + * holes_sanity_f * + *===========================================================================*/ +PRIVATE void holes_sanity_f(file, line) +char *file; +int line; +{ +#define myassert(c) { \ + if(!(c)) { \ + printf("holes_sanity_f:%s:%d: %s failed\n", file, line, #c); \ + util_stacktrace(); \ + vm_panic("assert failed.", NO_NUM); } \ + } + + int h, c = 0, n = 0; + struct hole *hp; + + /* Reset flags */ + for(h = 0; h < _NR_HOLES; h++) { + hole[h].freelist = 0; + hole[h].holelist = 0; + } + + /* Mark all holes on freelist. */ + for(hp = free_slots; hp; hp = hp->h_next) { + myassert(!hp->freelist); + myassert(!hp->holelist); + hp->freelist = 1; + myassert(c < _NR_HOLES); + c++; + n++; + } + + /* Mark all holes on holelist. */ + c = 0; + for(hp = hole_head; hp; hp = hp->h_next) { + myassert(!hp->freelist); + myassert(!hp->holelist); + hp->holelist = 1; + myassert(c < _NR_HOLES); + c++; + n++; + } + + /* Check there are exactly the right number of nodes. */ + myassert(n == _NR_HOLES); + + /* Make sure each slot is on exactly one of the list. */ + c = 0; + for(h = 0; h < _NR_HOLES; h++) { + hp = &hole[h]; + myassert(hp->holelist || hp->freelist); + myassert(!(hp->holelist && hp->freelist)); + myassert(c < _NR_HOLES); + c++; + } + + /* Make sure no holes overlap. */ + for(hp = hole_head; hp && hp->h_next; hp = hp->h_next) { + myassert(hp->holelist); + hp->holelist = 1; + /* No holes overlap. */ + myassert(hp->h_base + hp->h_len <= hp->h_next->h_base); + + /* No uncoalesced holes. */ + myassert(hp->h_base + hp->h_len < hp->h_next->h_base); + } +} +#endif + +/*===========================================================================* + * alloc_mem_f * + *===========================================================================*/ +PUBLIC phys_clicks alloc_mem_f(phys_clicks clicks, u32_t memflags) +{ +/* Allocate a block of memory from the free list using first fit. The block + * consists of a sequence of contiguous bytes, whose length in clicks is + * given by 'clicks'. A pointer to the block is returned. The block is + * always on a click boundary. This procedure is called when memory is + * needed for FORK or EXEC. + */ + register struct hole *hp, *prev_ptr; + phys_clicks old_base; + int s; + + if(vm_paged) { + vm_assert(CLICK_SIZE == VM_PAGE_SIZE); + return alloc_pages(clicks, memflags); + } + +CHECKHOLES; + + { + prev_ptr = NIL_HOLE; + hp = hole_head; + while (hp != NIL_HOLE) { + if (hp->h_len >= clicks) { + /* We found a hole that is big enough. Use it. */ + old_base = hp->h_base; /* remember where it started */ + hp->h_base += clicks; /* bite a piece off */ + hp->h_len -= clicks; /* ditto */ + + /* Delete the hole if used up completely. */ + if (hp->h_len == 0) del_slot(prev_ptr, hp); + + /* Anything special needs to happen? */ + if(memflags & PAF_CLEAR) { + if ((s= sys_memset(0, CLICK_SIZE*old_base, + CLICK_SIZE*clicks)) != OK) { + vm_panic("alloc_mem: sys_memset failed", s); + } + } + + /* Return the start address of the acquired block. */ +CHECKHOLES; + return(old_base); + } + + prev_ptr = hp; + hp = hp->h_next; + } + } +CHECKHOLES; + return(NO_MEM); +} + +/*===========================================================================* + * free_mem_f * + *===========================================================================*/ +PUBLIC void free_mem_f(phys_clicks base, phys_clicks clicks) +{ +/* Return a block of free memory to the hole list. The parameters tell where + * the block starts in physical memory and how big it is. The block is added + * to the hole list. If it is contiguous with an existing hole on either end, + * it is merged with the hole or holes. + */ + register struct hole *hp, *new_ptr, *prev_ptr; +CHECKHOLES; + + if (clicks == 0) return; + + if(vm_paged) { + vm_assert(CLICK_SIZE == VM_PAGE_SIZE); + free_pages(base, clicks); + return; + } + + if ( (new_ptr = free_slots) == NIL_HOLE) + vm_panic("hole table full", NO_NUM); + new_ptr->h_base = base; + new_ptr->h_len = clicks; + free_slots = new_ptr->h_next; + hp = hole_head; + + /* If this block's address is numerically less than the lowest hole currently + * available, or if no holes are currently available, put this hole on the + * front of the hole list. + */ + if (hp == NIL_HOLE || base <= hp->h_base) { + /* Block to be freed goes on front of the hole list. */ + new_ptr->h_next = hp; + hole_head = new_ptr; + merge(new_ptr); +CHECKHOLES; + return; + } + + /* Block to be returned does not go on front of hole list. */ + prev_ptr = NIL_HOLE; + while (hp != NIL_HOLE && base > hp->h_base) { + prev_ptr = hp; + hp = hp->h_next; + } + + /* We found where it goes. Insert block after 'prev_ptr'. */ + new_ptr->h_next = prev_ptr->h_next; + prev_ptr->h_next = new_ptr; + merge(prev_ptr); /* sequence is 'prev_ptr', 'new_ptr', 'hp' */ +CHECKHOLES; +} + +/*===========================================================================* + * del_slot * + *===========================================================================*/ +PRIVATE void del_slot(prev_ptr, hp) +/* pointer to hole entry just ahead of 'hp' */ +register struct hole *prev_ptr; +/* pointer to hole entry to be removed */ +register struct hole *hp; +{ +/* Remove an entry from the hole list. This procedure is called when a + * request to allocate memory removes a hole in its entirety, thus reducing + * the numbers of holes in memory, and requiring the elimination of one + * entry in the hole list. + */ + if (hp == hole_head) + hole_head = hp->h_next; + else + prev_ptr->h_next = hp->h_next; + + hp->h_next = free_slots; + hp->h_base = hp->h_len = 0; + free_slots = hp; +} + +/*===========================================================================* + * merge * + *===========================================================================*/ +PRIVATE void merge(hp) +register struct hole *hp; /* ptr to hole to merge with its successors */ +{ +/* Check for contiguous holes and merge any found. Contiguous holes can occur + * when a block of memory is freed, and it happens to abut another hole on + * either or both ends. The pointer 'hp' points to the first of a series of + * three holes that can potentially all be merged together. + */ + register struct hole *next_ptr; + + /* If 'hp' points to the last hole, no merging is possible. If it does not, + * try to absorb its successor into it and free the successor's table entry. + */ + if ( (next_ptr = hp->h_next) == NIL_HOLE) return; + if (hp->h_base + hp->h_len == next_ptr->h_base) { + hp->h_len += next_ptr->h_len; /* first one gets second one's mem */ + del_slot(hp, next_ptr); + } else { + hp = next_ptr; + } + + /* If 'hp' now points to the last hole, return; otherwise, try to absorb its + * successor into it. + */ + if ( (next_ptr = hp->h_next) == NIL_HOLE) return; + if (hp->h_base + hp->h_len == next_ptr->h_base) { + hp->h_len += next_ptr->h_len; + del_slot(hp, next_ptr); + } +} + +/*===========================================================================* + * mem_init * + *===========================================================================*/ +PUBLIC void mem_init(chunks) +struct memory *chunks; /* list of free memory chunks */ +{ +/* Initialize hole lists. There are two lists: 'hole_head' points to a linked + * list of all the holes (unused memory) in the system; 'free_slots' points to + * a linked list of table entries that are not in use. Initially, the former + * list has one entry for each chunk of physical memory, and the second + * list links together the remaining table slots. As memory becomes more + * fragmented in the course of time (i.e., the initial big holes break up into + * smaller holes), new table slots are needed to represent them. These slots + * are taken from the list headed by 'free_slots'. + */ + int i, first = 0; + register struct hole *hp; + + /* Put all holes on the free list. */ + for (hp = &hole[0]; hp < &hole[_NR_HOLES]; hp++) { + hp->h_next = hp + 1; + hp->h_base = hp->h_len = 0; + } + hole[_NR_HOLES-1].h_next = NIL_HOLE; + hole_head = NIL_HOLE; + free_slots = &hole[0]; + + /* Use the chunks of physical memory to allocate holes. */ + for (i=NR_MEMS-1; i>=0; i--) { + if (chunks[i].size > 0) { + phys_bytes from = CLICK2ABS(chunks[i].base), + to = CLICK2ABS(chunks[i].base+chunks[i].size)-1; + if(first || from < mem_low) mem_low = from; + if(first || to > mem_high) mem_high = to; + FREE_MEM(chunks[i].base, chunks[i].size); + first = 0; + } + } + + CHECKHOLES; +} + +/*===========================================================================* + * alloc_pages * + *===========================================================================*/ +PRIVATE PUBLIC phys_bytes alloc_pages(int pages, int memflags) +{ + phys_bytes bytes, p, nextp, prevp = NO_MEM; + phys_bytes prevsize = 0; + +#if SANITYCHECKS + vir_bytes avail1, avail2, chunks1, chunks2; + availbytes(&avail1, &chunks1); +#endif + + vm_assert(pages > 0); + bytes = CLICK2ABS(pages); + vm_assert(ABS2CLICK(bytes) == pages); + +#if SANITYCHECKS +#define ALLOCRETURNCHECK \ + availbytes(&avail2, &chunks2); \ + vm_assert(avail1 - bytes == avail2); \ + vm_assert(chunks1 == chunks2 || chunks1-1 == chunks2); \ + if(verbosealloc) \ + printf("memory: 0x%lx bytes in %d chunks\n", avail2, chunks2); +#else +#define ALLOCRETURNCHECK +#endif + + + for(p = free_pages_head; p != NO_MEM; p = nextp) { + phys_bytes thissize, ret; + GET_PARAMS(p, thissize, nextp); + if(thissize >= bytes) { + /* We found a chunk that's big enough. */ + + ret = p + thissize - bytes; + thissize -= bytes; + + if(thissize == 0) { + /* Special case: remove this link entirely. */ + if(prevp == NO_MEM) + free_pages_head = nextp; + else { + vm_assert(prevsize > 0); + SET_PARAMS(prevp, prevsize, nextp); + } + } else { + /* Remove memory from this chunk. */ + SET_PARAMS(p, thissize, nextp); + } + + /* Clear memory if requested. */ + if(memflags & PAF_CLEAR) { + int s; + if ((s= sys_memset(0, ret, bytes)) != OK) { + vm_panic("alloc_pages: sys_memset failed", s); + } + } + + /* Check if returned range is actual good memory. */ + vm_assert_range(ret, bytes); + + ALLOCRETURNCHECK; + + /* Return it in clicks. */ + return ABS2CLICK(ret); + } + prevp = p; + prevsize = thissize; + } + return NO_MEM; +} + +/*===========================================================================* + * free_pages * + *===========================================================================*/ +PRIVATE PUBLIC void free_pages(phys_bytes pageno, int npages) +{ + phys_bytes p, origsize, + size, nextaddr, thissize, prevp = NO_MEM, pageaddr; + +#if SANITYCHECKS + vir_bytes avail1, avail2, chunks1, chunks2; + availbytes(&avail1, &chunks1); +#endif + +#if SANITYCHECKS +#define FREERETURNCHECK \ + availbytes(&avail2, &chunks2); \ + vm_assert(avail1 + origsize == avail2); \ + vm_assert(chunks1 == chunks2 || chunks1+1 == chunks2 || chunks1-1 == chunks2); \ + if(verbosealloc) \ + printf("memory: 0x%lx bytes in %d chunks\n", avail2, chunks2); +#else +#define FREERETURNCHECK +#endif + + /* Basic sanity check. */ + vm_assert(npages > 0); + vm_assert(pageno != NO_MEM); /* Page number must be reasonable. */ + + /* Convert page and pages to bytes. */ + pageaddr = CLICK2ABS(pageno); + origsize = size = npages * VM_PAGE_SIZE; /* Size in bytes. */ + vm_assert(pageaddr != NO_MEM); + vm_assert(ABS2CLICK(pageaddr) == pageno); + vm_assert_range(pageaddr, size); + + /* More sanity checks. */ + vm_assert(ABS2CLICK(size) == npages); /* Sanity. */ + vm_assert(pageaddr + size > pageaddr); /* Must not overflow. */ + + /* Special case: no free pages. */ + if(free_pages_head == NO_MEM) { + free_pages_head = pageaddr; + SET_PARAMS(pageaddr, size, NO_MEM); + FREERETURNCHECK; + return; + } + + /* Special case: the free block is before the current head. */ + if(pageaddr < free_pages_head) { + phys_bytes newsize, newnext, headsize, headnext; + vm_assert(pageaddr + size <= free_pages_head); + GET_PARAMS(free_pages_head, headsize, headnext); + newsize = size; + if(pageaddr + size == free_pages_head) { + /* Special case: contiguous. */ + newsize += headsize; + newnext = headnext; + } else { + newnext = free_pages_head; + } + SET_PARAMS(pageaddr, newsize, newnext); + free_pages_head = pageaddr; + FREERETURNCHECK; + return; + } + + /* Find where to put the block in the free list. */ + for(p = free_pages_head; p < pageaddr; p = nextaddr) { + GET_PARAMS(p, thissize, nextaddr); + + if(nextaddr == NO_MEM) { + /* Special case: page is at the end of the list. */ + if(p + thissize == pageaddr) { + /* Special case: contiguous. */ + SET_PARAMS(p, thissize + size, NO_MEM); + FREERETURNCHECK; + } else { + SET_PARAMS(p, thissize, pageaddr); + SET_PARAMS(pageaddr, size, NO_MEM); + FREERETURNCHECK; + } + return; + } + + prevp = p; + } + + /* Normal case: insert page block between two others. + * The first block starts at 'prevp' and is 'thissize'. + * The second block starts at 'p' and is 'nextsize'. + * The block that has to come in between starts at + * 'pageaddr' and is size 'size'. + */ + vm_assert(p != NO_MEM); + vm_assert(prevp != NO_MEM); + vm_assert(prevp < p); + vm_assert(p == nextaddr); + +#if SANITYCHECKS + { + vir_bytes prevpsize, prevpnext; + GET_PARAMS(prevp, prevpsize, prevpnext); + vm_assert(prevpsize == thissize); + vm_assert(prevpnext == p); + + availbytes(&avail2, &chunks2); + vm_assert(avail1 == avail2); + } +#endif + + if(prevp + thissize == pageaddr) { + /* Special case: first block is contiguous with freed one. */ + phys_bytes newsize = thissize + size; + SET_PARAMS(prevp, newsize, p); + pageaddr = prevp; + size = newsize; + } else { + SET_PARAMS(prevp, thissize, pageaddr); + } + + /* The block has been inserted (and possibly merged with the + * first one). Check if it has to be merged with the second one. + */ + + if(pageaddr + size == p) { + phys_bytes nextsize, nextnextaddr; + /* Special case: freed block is contiguous with next one. */ + GET_PARAMS(p, nextsize, nextnextaddr); + SET_PARAMS(pageaddr, size+nextsize, nextnextaddr); + FREERETURNCHECK; + } else { + SET_PARAMS(pageaddr, size, p); + FREERETURNCHECK; + } + + return; +} + + +#define NR_DMA 16 + +PRIVATE struct dmatab +{ + int dt_flags; + endpoint_t dt_proc; + phys_bytes dt_base; + phys_bytes dt_size; + phys_clicks dt_seg_base; + phys_clicks dt_seg_size; +} dmatab[NR_DMA]; + +#define DTF_INUSE 1 +#define DTF_RELEASE_DMA 2 +#define DTF_RELEASE_SEG 4 + +/*===========================================================================* + * do_adddma * + *===========================================================================*/ +PUBLIC int do_adddma(message *msg) +{ + endpoint_t req_proc_e, target_proc_e; + int i, proc_n; + phys_bytes base, size; + struct vmproc *vmp; + + req_proc_e= msg->VMAD_REQ; + target_proc_e= msg->VMAD_EP; + base= msg->VMAD_START; + size= msg->VMAD_SIZE; + + /* Find empty slot */ + for (i= 0; i= NR_DMA) + { + printf("vm:do_adddma: dma table full\n"); + for (i= 0; ivm_flags |= VMF_HAS_DMA; + + dmatab[i].dt_flags= DTF_INUSE; + dmatab[i].dt_proc= target_proc_e; + dmatab[i].dt_base= base; + dmatab[i].dt_size= size; + + return OK; +} + +/*===========================================================================* + * do_deldma * + *===========================================================================*/ +PUBLIC int do_deldma(message *msg) +{ + endpoint_t req_proc_e, target_proc_e; + int i, j, proc_n; + phys_bytes base, size; + struct vmproc *vmp; + + req_proc_e= msg->VMDD_REQ; + target_proc_e= msg->VMDD_EP; + base= msg->VMDD_START; + size= msg->VMDD_SIZE; + + /* Find slot */ + for (i= 0; i= NR_DMA) + { + printf("vm:do_deldma: slot not found\n"); + return ESRCH; + } + + if (dmatab[i].dt_flags & DTF_RELEASE_SEG) + { + /* Check if we have to release the segment */ + for (j= 0; j= NR_DMA) + { + /* Last segment */ + FREE_MEM(dmatab[i].dt_seg_base, + dmatab[i].dt_seg_size); + } + } + + dmatab[i].dt_flags &= ~DTF_INUSE; + + return OK; +} + +/*===========================================================================* + * do_getdma * + *===========================================================================*/ +PUBLIC int do_getdma(message *msg) +{ + endpoint_t target_proc_e; + int i, proc_n; + phys_bytes base, size; + struct vmproc *vmp; + + /* Find slot to report */ + for (i= 0; iVMGD_PROCP= dmatab[i].dt_proc; + msg->VMGD_BASEP= dmatab[i].dt_base; + msg->VMGD_SIZEP= dmatab[i].dt_size; + + return OK; + } + + /* Nothing */ + return EAGAIN; +} + + + +/*===========================================================================* + * release_dma * + *===========================================================================*/ +PUBLIC void release_dma(struct vmproc *vmp) +{ + int i, found_one; + + vm_panic("release_dma not done", NO_NUM); +#if 0 + + found_one= FALSE; + for (i= 0; ivm_endpoint) + continue; + dmatab[i].dt_flags |= DTF_RELEASE_DMA | DTF_RELEASE_SEG; + dmatab[i].dt_seg_base= base; + dmatab[i].dt_seg_size= size; + found_one= TRUE; + } + + if (!found_one) + FREE_MEM(base, size); + + msg->VMRD_FOUND = found_one; +#endif + + return; +} + +/*===========================================================================* + * do_allocmem * + *===========================================================================*/ +PUBLIC int do_allocmem(message *m) +{ + phys_clicks mem; + + if((mem=ALLOC_MEM((phys_clicks) m->VMAM_CLICKS, PAF_CLEAR)) == NO_MEM) { + return ENOMEM; + } + + m->VMAM_MEMBASE = mem; + + printf("VM: do_allocmem: 0x%lx clicks OK at 0x%lx\n", m->VMAM_CLICKS, mem); + + return OK; +} + diff --git a/servers/vm/asynsend.c b/servers/vm/asynsend.c new file mode 100644 index 000000000..19e04194b --- /dev/null +++ b/servers/vm/asynsend.c @@ -0,0 +1,67 @@ + +#define _SYSTEM 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "proto.h" +#include "util.h" + +#define SENDSLOTS _NR_PROCS + +PRIVATE asynmsg_t msgtable[SENDSLOTS]; +PRIVATE size_t msgtable_n= SENDSLOTS; + +PUBLIC int asynsend(dst, mp) +endpoint_t dst; +message *mp; +{ + int i; + unsigned flags; + + /* Find slot in table */ + for (i= 0; i= msgtable_n) + vm_panic("asynsend: should resize table", i); + msgtable[i].dst= dst; + msgtable[i].msg= *mp; + msgtable[i].flags= AMF_VALID; /* Has to be last. The kernel + * scans this table while we are + * sleeping. + */ + + /* Tell the kernel to rescan the table */ + return senda(msgtable, msgtable_n); +} + diff --git a/servers/vm/break.c b/servers/vm/break.c new file mode 100644 index 000000000..0c6822217 --- /dev/null +++ b/servers/vm/break.c @@ -0,0 +1,179 @@ +/* The MINIX model of memory allocation reserves a fixed amount of memory for + * the combined text, data, and stack segments. The amount used for a child + * process created by FORK is the same as the parent had. If the child does + * an EXEC later, the new size is taken from the header of the file EXEC'ed. + * + * The layout in memory consists of the text segment, followed by the data + * segment, followed by a gap (unused memory), followed by the stack segment. + * The data segment grows upward and the stack grows downward, so each can + * take memory from the gap. If they meet, the process must be killed. The + * procedures in this file deal with the growth of the data and stack segments. + * + * The entry points into this file are: + * do_brk: BRK/SBRK system calls to grow or shrink the data segment + * adjust: see if a proposed segment adjustment is allowed + */ + +#define _SYSTEM 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "glo.h" +#include "vm.h" +#include "proto.h" +#include "util.h" + +#define DATA_CHANGED 1 /* flag value when data segment size changed */ +#define STACK_CHANGED 2 /* flag value when stack size changed */ + +/*===========================================================================* + * do_brk * + *===========================================================================*/ +PUBLIC int do_brk(message *msg) +{ +/* Perform the brk(addr) system call. + * The parameter, 'addr' is the new virtual address in D space. + */ + int proc; + + if(vm_isokendpt(msg->VMB_ENDPOINT, &proc) != OK) { + printf("VM: bogus endpoint VM_BRK %d\n", msg->VMB_ENDPOINT); + return EINVAL; + } + + return real_brk(&vmproc[proc], (vir_bytes) msg->VMB_ADDR); +} + +/*===========================================================================* + * adjust * + *===========================================================================*/ +PUBLIC int adjust(rmp, data_clicks, sp) +struct vmproc *rmp; /* whose memory is being adjusted? */ +vir_clicks data_clicks; /* how big is data segment to become? */ +vir_bytes sp; /* new value of sp */ +{ +/* See if data and stack segments can coexist, adjusting them if need be. + * Memory is never allocated or freed. Instead it is added or removed from the + * gap between data segment and stack segment. If the gap size becomes + * negative, the adjustment of data or stack fails and ENOMEM is returned. + */ + + register struct mem_map *mem_sp, *mem_dp; + vir_clicks sp_click, gap_base, sp_lower, old_clicks; + int changed, r; + long base_of_stack, sp_delta; /* longs avoid certain problems */ + + mem_dp = &rmp->vm_arch.vm_seg[D]; /* pointer to data segment map */ + mem_sp = &rmp->vm_arch.vm_seg[S]; /* pointer to stack segment map */ + changed = 0; /* set when either segment changed */ + + /* See if stack size has gone negative (i.e., sp too close to 0xFFFF...) */ + base_of_stack = (long) mem_sp->mem_vir + (long) mem_sp->mem_len; + sp_click = sp >> CLICK_SHIFT; /* click containing sp */ + if (sp_click >= base_of_stack) + { + return(ENOMEM); /* sp too high */ + } + + /* Compute size of gap between stack and data segments. */ + sp_delta = (long) mem_sp->mem_vir - (long) sp_click; + sp_lower = (sp_delta > 0 ? sp_click : mem_sp->mem_vir); + + /* Add a safety margin for future stack growth. Impossible to do right. */ +#define SAFETY_BYTES (384 * sizeof(char *)) +#define SAFETY_CLICKS ((SAFETY_BYTES + CLICK_SIZE - 1) / CLICK_SIZE) + gap_base = mem_dp->mem_vir + data_clicks + SAFETY_CLICKS; + if (sp_lower < gap_base) + { + return(ENOMEM); /* data and stack collided */ + } + + /* Update data length (but not data orgin) on behalf of brk() system call. */ + old_clicks = mem_dp->mem_len; + if (data_clicks != mem_dp->mem_len) { + mem_dp->mem_len = data_clicks; + changed |= DATA_CHANGED; + } + + /* Update stack length and origin due to change in stack pointer. */ + if (sp_delta > 0) { + mem_sp->mem_vir -= sp_delta; + mem_sp->mem_phys -= sp_delta; + mem_sp->mem_len += sp_delta; + changed |= STACK_CHANGED; + } + + /* Do the new data and stack segment sizes fit in the address space? */ + r = (rmp->vm_arch.vm_seg[D].mem_vir + rmp->vm_arch.vm_seg[D].mem_len > + rmp->vm_arch.vm_seg[S].mem_vir) ? ENOMEM : OK; + + if(r == OK && (rmp->vm_flags & VMF_HASPT) && + rmp->vm_endpoint != VM_PROC_NR) { + vm_assert(rmp->vm_heap); + if(old_clicks < data_clicks) { + vir_bytes more; + more = (data_clicks - old_clicks) << CLICK_SHIFT; + if(map_region_extend(rmp->vm_heap, more) != OK) { + printf("VM: brk: map_region_extend failed\n"); + return ENOMEM; + } + } else if(old_clicks > data_clicks) { + vir_bytes less; + less = (old_clicks - data_clicks) << CLICK_SHIFT; + if(map_region_shrink(rmp->vm_heap, less) != OK) { + printf("VM: brk: map_region_shrink failed\n"); + return ENOMEM; + } + } + } + + if (r == OK) + return(OK); + + /* New sizes don't fit or require too many page/segment registers. Restore.*/ + if (changed & DATA_CHANGED) mem_dp->mem_len = old_clicks; + if (changed & STACK_CHANGED) { + mem_sp->mem_vir += sp_delta; + mem_sp->mem_phys += sp_delta; + mem_sp->mem_len -= sp_delta; + } + return(ENOMEM); +} + +/*===========================================================================* + * real_brk * + *===========================================================================*/ +PUBLIC int real_brk(vmp, v) +struct vmproc *vmp; +vir_bytes v; +{ + vir_bytes new_sp; + vir_clicks new_clicks; + int r; + + new_clicks = (vir_clicks) ( ((long) v + CLICK_SIZE - 1) >> CLICK_SHIFT); + if (new_clicks < vmp->vm_arch.vm_seg[D].mem_vir) { + printf("VM: real_brk failed because new_clicks too high: %d\n", + new_clicks); + return(ENOMEM); + } + new_clicks -= vmp->vm_arch.vm_seg[D].mem_vir; + if ((r=get_stack_ptr(vmp->vm_endpoint, &new_sp)) != OK) + vm_panic("couldn't get stack pointer", r); + r = adjust(vmp, new_clicks, new_sp); + return r; +} diff --git a/servers/vm/exec.c b/servers/vm/exec.c new file mode 100644 index 000000000..44649d566 --- /dev/null +++ b/servers/vm/exec.c @@ -0,0 +1,413 @@ + +#define _SYSTEM 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "glo.h" +#include "proto.h" +#include "util.h" +#include "vm.h" +#include "region.h" +#include "sanitycheck.h" + +#include "memory.h" + +FORWARD _PROTOTYPE( int new_mem, (struct vmproc *vmp, struct vmproc *sh_vmp, + vir_bytes text_bytes, vir_bytes data_bytes, vir_bytes bss_bytes, + vir_bytes stk_bytes, phys_bytes tot_bytes) ); +FORWARD _PROTOTYPE( u32_t find_kernel_top, (void)); + +/*===========================================================================* + * find_share * + *===========================================================================*/ +PUBLIC struct vmproc *find_share(vmp_ign, ino, dev, ctime) +struct vmproc *vmp_ign; /* process that should not be looked at */ +ino_t ino; /* parameters that uniquely identify a file */ +dev_t dev; +time_t ctime; +{ +/* Look for a process that is the file in execution. Don't + * accidentally "find" vmp_ign, because it is the process on whose behalf this + * call is made. + */ + struct vmproc *vmp; + for (vmp = &vmproc[0]; vmp < &vmproc[NR_PROCS]; vmp++) { + if (!(vmp->vm_flags & VMF_INUSE)) continue; + if (!(vmp->vm_flags & VMF_SEPARATE)) continue; + if (vmp->vm_flags & VMF_HASPT) continue; + if (vmp == vmp_ign) continue; + if (vmp->vm_ino != ino) continue; + if (vmp->vm_dev != dev) continue; + if (vmp->vm_ctime != ctime) continue; + return vmp; + } + return(NULL); +} + + +/*===========================================================================* + * exec_newmem * + *===========================================================================*/ +PUBLIC int do_exec_newmem(message *msg) +{ + int r, proc_e, proc_n; + vir_bytes stack_top; + vir_clicks tc, dc, sc, totc, dvir, s_vir; + struct vmproc *vmp, *sh_mp; + char *ptr; + struct exec_newmem args; + + SANITYCHECK(SCL_FUNCTIONS); + + proc_e= msg->VMEN_ENDPOINT; + if (vm_isokendpt(proc_e, &proc_n) != OK) + { + printf("VM:exec_newmem: bad endpoint %d from %d\n", + proc_e, msg->m_source); + return ESRCH; + } + vmp= &vmproc[proc_n]; + ptr= msg->VMEN_ARGSPTR; + + if(msg->VMEN_ARGSSIZE != sizeof(args)) { + printf("VM:exec_newmem: args size %d != %ld\n", + msg->VMEN_ARGSSIZE, sizeof(args)); + return EINVAL; + } +SANITYCHECK(SCL_DETAIL); + + r= sys_datacopy(msg->m_source, (vir_bytes)ptr, + SELF, (vir_bytes)&args, sizeof(args)); + if (r != OK) + vm_panic("exec_newmem: sys_datacopy failed", r); + + /* Check to see if segment sizes are feasible. */ + tc = ((unsigned long) args.text_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; + dc = (args.data_bytes+args.bss_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; + totc = (args.tot_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; + sc = (args.args_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; + if (dc >= totc) return(ENOEXEC); /* stack must be at least 1 click */ + + dvir = (args.sep_id ? 0 : tc); + s_vir = dvir + (totc - sc); + r = (dvir + dc > s_vir) ? ENOMEM : OK; + if (r != OK) + return r; + + /* Can the process' text be shared with that of one already running? */ + if(!vm_paged) { + sh_mp = find_share(vmp, args.st_ino, args.st_dev, args.st_ctime); + } else { + sh_mp = NULL; + } + + /* Allocate new memory and release old memory. Fix map and tell + * kernel. + */ + r = new_mem(vmp, sh_mp, args.text_bytes, args.data_bytes, + args.bss_bytes, args.args_bytes, args.tot_bytes); + if (r != OK) return(r); + + /* Save file identification to allow it to be shared. */ + vmp->vm_ino = args.st_ino; + vmp->vm_dev = args.st_dev; + vmp->vm_ctime = args.st_ctime; + + stack_top= ((vir_bytes)vmp->vm_arch.vm_seg[S].mem_vir << CLICK_SHIFT) + + ((vir_bytes)vmp->vm_arch.vm_seg[S].mem_len << CLICK_SHIFT); + + /* set/clear separate I&D flag */ + if (args.sep_id) + vmp->vm_flags |= VMF_SEPARATE; + else + vmp->vm_flags &= ~VMF_SEPARATE; + + + msg->VMEN_STACK_TOP = (void *) stack_top; + msg->VMEN_FLAGS = 0; + if (!sh_mp) /* Load text if sh_mp = NULL */ + msg->VMEN_FLAGS |= EXC_NM_RF_LOAD_TEXT; + + return OK; +} + +/*===========================================================================* + * new_mem * + *===========================================================================*/ +PRIVATE int new_mem(rmp, sh_mp, text_bytes, data_bytes, + bss_bytes,stk_bytes,tot_bytes) +struct vmproc *rmp; /* process to get a new memory map */ +struct vmproc *sh_mp; /* text can be shared with this process */ +vir_bytes text_bytes; /* text segment size in bytes */ +vir_bytes data_bytes; /* size of initialized data in bytes */ +vir_bytes bss_bytes; /* size of bss in bytes */ +vir_bytes stk_bytes; /* size of initial stack segment in bytes */ +phys_bytes tot_bytes; /* total memory to allocate, including gap */ +{ +/* Allocate new memory and release the old memory. Change the map and report + * the new map to the kernel. Zero the new core image's bss, gap and stack. + */ + + vir_clicks text_clicks, data_clicks, gap_clicks, stack_clicks, tot_clicks; + phys_bytes bytes, base, bss_offset; + int s, r2; + static u32_t kernel_top = 0; + + SANITYCHECK(SCL_FUNCTIONS); + + /* No need to allocate text if it can be shared. */ + if (sh_mp != NULL) { + text_bytes = 0; + vm_assert(!vm_paged); + } + + /* Acquire the new memory. Each of the 4 parts: text, (data+bss), gap, + * and stack occupies an integral number of clicks, starting at click + * boundary. The data and bss parts are run together with no space. + */ + text_clicks = ((unsigned long) text_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; + data_clicks = (data_bytes + bss_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; + stack_clicks = (stk_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; + tot_clicks = (tot_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; + gap_clicks = tot_clicks - data_clicks - stack_clicks; + if ( (int) gap_clicks < 0) return(ENOMEM); + +SANITYCHECK(SCL_DETAIL); + + + /* We've got memory for the new core image. Release the old one. */ + + if(rmp->vm_flags & VMF_HASPT) { + /* Free page table and memory allocated by pagetable functions. */ + rmp->vm_flags &= ~VMF_HASPT; + free_proc(rmp); + } else { + + if (find_share(rmp, rmp->vm_ino, rmp->vm_dev, rmp->vm_ctime) == NULL) { + /* No other process shares the text segment, so free it. */ + FREE_MEM(rmp->vm_arch.vm_seg[T].mem_phys, rmp->vm_arch.vm_seg[T].mem_len); + } + + /* Free the data and stack segments. */ + FREE_MEM(rmp->vm_arch.vm_seg[D].mem_phys, + rmp->vm_arch.vm_seg[S].mem_vir + + rmp->vm_arch.vm_seg[S].mem_len + - rmp->vm_arch.vm_seg[D].mem_vir); + } + + /* We have now passed the point of no return. The old core image has been + * forever lost, memory for a new core image has been allocated. Set up + * and report new map. + */ + + if(vm_paged) { + vir_bytes hole_clicks; + + if(pt_new(&rmp->vm_pt) != OK) + vm_panic("exec_newmem: no new pagetable", NO_NUM); + SANITYCHECK(SCL_DETAIL); + + if(!map_proc_kernel(rmp)) { + printf("VM: exec: map_proc_kernel failed\n"); + return ENOMEM; + } + + if(!kernel_top) + kernel_top = find_kernel_top(); + + /* Place text at kernel top. */ + rmp->vm_arch.vm_seg[T].mem_phys = kernel_top; + rmp->vm_arch.vm_seg[T].mem_vir = 0; + rmp->vm_arch.vm_seg[T].mem_len = text_clicks; + + rmp->vm_offset = CLICK2ABS(kernel_top); + + vm_assert(!sh_mp); + /* page mapping flags for code */ +#define TEXTFLAGS (PTF_PRESENT | PTF_USER | PTF_WRITE) + SANITYCHECK(SCL_DETAIL); + if(text_clicks > 0) { + if(!map_page_region(rmp, CLICK2ABS(kernel_top), 0, + CLICK2ABS(rmp->vm_arch.vm_seg[T].mem_len), 0, + VR_ANON | VR_WRITABLE, 0)) { + SANITYCHECK(SCL_DETAIL); + printf("VM: map_page_region failed (text)\n"); + return(ENOMEM); + } + SANITYCHECK(SCL_DETAIL); + } + SANITYCHECK(SCL_DETAIL); + + /* Allocate memory for data (including bss, but not including gap + * or stack), make sure it's cleared, and map it in after text + * (if any). + */ + if(!(rmp->vm_heap = map_page_region(rmp, + CLICK2ABS(kernel_top + text_clicks), 0, + CLICK2ABS(data_clicks), 0, VR_ANON | VR_WRITABLE, 0))) { + printf("VM: exec: map_page_region for data failed\n"); + return ENOMEM; + } + + map_region_set_tag(rmp->vm_heap, VRT_HEAP); + + /* How many address space clicks between end of data + * and start of stack? + * VM_STACKTOP is the first address after the stack, as addressed + * from within the user process. + */ + hole_clicks = VM_STACKTOP >> CLICK_SHIFT; + hole_clicks -= data_clicks + stack_clicks + gap_clicks; + + if(!map_page_region(rmp, + CLICK2ABS(kernel_top + text_clicks + data_clicks + hole_clicks), + 0, CLICK2ABS(stack_clicks+gap_clicks), 0, + VR_ANON | VR_WRITABLE, 0) != OK) { + vm_panic("map_page_region failed for stack", NO_NUM); + } + + rmp->vm_arch.vm_seg[D].mem_phys = kernel_top + text_clicks; + rmp->vm_arch.vm_seg[D].mem_vir = 0; + rmp->vm_arch.vm_seg[D].mem_len = data_clicks; + + + rmp->vm_arch.vm_seg[S].mem_phys = kernel_top + + text_clicks + data_clicks + gap_clicks + hole_clicks; + rmp->vm_arch.vm_seg[S].mem_vir = data_clicks + gap_clicks + hole_clicks; + + /* Pretend the stack is the full size of the data segment, so + * we get a full-sized data segment, up to VM_DATATOP. + * After sys_newmap(),, change the stack to what we know the + * stack to be (up to VM_STACKTOP). + */ + rmp->vm_arch.vm_seg[S].mem_len = (VM_DATATOP >> CLICK_SHIFT) - + rmp->vm_arch.vm_seg[S].mem_vir - kernel_top - text_clicks; + + /* Where are we allowed to start using the rest of the virtual + * address space? + */ + rmp->vm_stacktop = VM_STACKTOP; + + /* What is the final size of the data segment in bytes? */ + rmp->vm_arch.vm_data_top = + (rmp->vm_arch.vm_seg[S].mem_vir + + rmp->vm_arch.vm_seg[S].mem_len) << CLICK_SHIFT; + + rmp->vm_flags |= VMF_HASPT; + + if((s=sys_newmap(rmp->vm_endpoint, rmp->vm_arch.vm_seg)) != OK) { + vm_panic("sys_newmap (vm) failed", s); + } + + + /* This is the real stack clicks. */ + rmp->vm_arch.vm_seg[S].mem_len = stack_clicks; + + } else { + phys_clicks new_base; + + new_base = ALLOC_MEM(text_clicks + tot_clicks, 0); + if (new_base == NO_MEM) return(ENOMEM); + + if (sh_mp != NULL) { + /* Share the text segment. */ + rmp->vm_arch.vm_seg[T] = sh_mp->vm_arch.vm_seg[T]; + } else { + rmp->vm_arch.vm_seg[T].mem_phys = new_base; + rmp->vm_arch.vm_seg[T].mem_vir = 0; + rmp->vm_arch.vm_seg[T].mem_len = text_clicks; + + if (text_clicks > 0) + { + /* Zero the last click of the text segment. Otherwise the + * part of that click may remain unchanged. + */ + base = (phys_bytes)(new_base+text_clicks-1) << CLICK_SHIFT; + if ((s= sys_memset(0, base, CLICK_SIZE)) != OK) + vm_panic("new_mem: sys_memset failed", s); + } + } + + /* No paging stuff. */ + rmp->vm_flags &= ~VMF_HASPT; + rmp->vm_regions = NULL; + + rmp->vm_arch.vm_seg[D].mem_phys = new_base + text_clicks; + rmp->vm_arch.vm_seg[D].mem_vir = 0; + rmp->vm_arch.vm_seg[D].mem_len = data_clicks; + rmp->vm_arch.vm_seg[S].mem_phys = rmp->vm_arch.vm_seg[D].mem_phys + + data_clicks + gap_clicks; + rmp->vm_arch.vm_seg[S].mem_vir = rmp->vm_arch.vm_seg[D].mem_vir + + data_clicks + gap_clicks; + rmp->vm_arch.vm_seg[S].mem_len = stack_clicks; + rmp->vm_stacktop = + CLICK2ABS(rmp->vm_arch.vm_seg[S].mem_vir + + rmp->vm_arch.vm_seg[S].mem_len); + + rmp->vm_arch.vm_data_top = + (rmp->vm_arch.vm_seg[S].mem_vir + + rmp->vm_arch.vm_seg[S].mem_len) << CLICK_SHIFT; + + if((r2=sys_newmap(rmp->vm_endpoint, rmp->vm_arch.vm_seg)) != OK) { + /* report new map to the kernel */ + vm_panic("sys_newmap failed", r2); + } + + /* Zero the bss, gap, and stack segment. */ + bytes = (phys_bytes)(data_clicks + gap_clicks + stack_clicks) << CLICK_SHIFT; + base = (phys_bytes) rmp->vm_arch.vm_seg[D].mem_phys << CLICK_SHIFT; + bss_offset = (data_bytes >> CLICK_SHIFT) << CLICK_SHIFT; + base += bss_offset; + bytes -= bss_offset; + + if ((s=sys_memset(0, base, bytes)) != OK) { + vm_panic("new_mem can't zero", s); + } + } + + /* Whether vm_pt is NULL or a new pagetable, tell kernel about it. */ + if((s=pt_bind(&rmp->vm_pt, rmp)) != OK) + vm_panic("exec_newmem: pt_bind failed", s); + +SANITYCHECK(SCL_FUNCTIONS); + + return(OK); +} + +/*===========================================================================* + * find_kernel_top * + *===========================================================================*/ +PRIVATE u32_t find_kernel_top(void) +{ +/* Find out where the kernel is, so we know where to start mapping + * user processes. + */ + u32_t kernel_top = 0; +#define MEMTOP(v, i) \ + (vmproc[v].vm_arch.vm_seg[i].mem_phys + vmproc[v].vm_arch.vm_seg[i].mem_len) + vm_assert(vmproc[VMP_SYSTEM].vm_flags & VMF_INUSE); + kernel_top = MEMTOP(VMP_SYSTEM, T); + kernel_top = MAX(kernel_top, MEMTOP(VMP_SYSTEM, D)); + kernel_top = MAX(kernel_top, MEMTOP(VMP_SYSTEM, S)); + vm_assert(kernel_top); + + return kernel_top; +} + diff --git a/servers/vm/exit.c b/servers/vm/exit.c new file mode 100644 index 000000000..9c80a9d4f --- /dev/null +++ b/servers/vm/exit.c @@ -0,0 +1,118 @@ + +#define _SYSTEM 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "glo.h" +#include "proto.h" +#include "util.h" +#include "sanitycheck.h" + +PUBLIC void free_proc(struct vmproc *vmp) +{ + vmp->vm_flags &= ~VMF_HASPT; + pt_free(&vmp->vm_pt); + map_free_proc(vmp); + vmp->vm_regions = NULL; +#if VMSTATS + vmp->vm_bytecopies = 0; +#endif +} + +PUBLIC void clear_proc(struct vmproc *vmp) +{ + vmp->vm_regions = NULL; + vmp->vm_callback = NULL; /* No pending vfs callback. */ + vmp->vm_flags = 0; /* Clear INUSE, so slot is free. */ + vmp->vm_count = 0; + vmp->vm_heap = NULL; +#if VMSTATS + vmp->vm_bytecopies = 0; +#endif +} + +/*===========================================================================* + * do_exit * + *===========================================================================*/ +PUBLIC int do_exit(message *msg) +{ + int proc; + struct vmproc *vmp; + +SANITYCHECK(SCL_FUNCTIONS); + + if(vm_isokendpt(msg->VME_ENDPOINT, &proc) != OK) { + printf("VM: bogus endpoint VM_EXIT %d\n", msg->VME_ENDPOINT); + return EINVAL; + } + vmp = &vmproc[proc]; + if(!(vmp->vm_flags & VMF_EXITING)) { + printf("VM: unannounced VM_EXIT %d\n", msg->VME_ENDPOINT); + return EINVAL; + } + + if(vmp->vm_flags & VMF_HAS_DMA) { + release_dma(vmp); + } else if(vmp->vm_flags & VMF_HASPT) { + /* Free pagetable and pages allocated by pt code. */ +SANITYCHECK(SCL_DETAIL); + free_proc(vmp); +SANITYCHECK(SCL_DETAIL); + } else { + /* Free the data and stack segments. */ + FREE_MEM(vmp->vm_arch.vm_seg[D].mem_phys, + vmp->vm_arch.vm_seg[S].mem_vir + + vmp->vm_arch.vm_seg[S].mem_len - + vmp->vm_arch.vm_seg[D].mem_vir); + + if (find_share(vmp, vmp->vm_ino, vmp->vm_dev, vmp->vm_ctime) == NULL) { + /* No other process shares the text segment, + * so free it. + */ + FREE_MEM(vmp->vm_arch.vm_seg[T].mem_phys, + vmp->vm_arch.vm_seg[T].mem_len); + } + } +SANITYCHECK(SCL_DETAIL); + + /* Reset process slot fields. */ + clear_proc(vmp); + +SANITYCHECK(SCL_FUNCTIONS); + return OK; +} + +/*===========================================================================* + * do_willexit * + *===========================================================================*/ +PUBLIC int do_willexit(message *msg) +{ + int proc; + struct vmproc *vmp; + + if(vm_isokendpt(msg->VMWE_ENDPOINT, &proc) != OK) { + printf("VM: bogus endpoint VM_EXITING %d\n", + msg->VMWE_ENDPOINT); + return EINVAL; + } + vmp = &vmproc[proc]; + + vmp->vm_flags |= VMF_EXITING; + + return OK; +} + diff --git a/servers/vm/fork.c b/servers/vm/fork.c new file mode 100644 index 000000000..8a5aa6ae7 --- /dev/null +++ b/servers/vm/fork.c @@ -0,0 +1,145 @@ + +#define _SYSTEM 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "glo.h" +#include "vm.h" +#include "proto.h" +#include "util.h" +#include "sanitycheck.h" +#include "region.h" + +/*===========================================================================* + * do_fork * + *===========================================================================*/ +PUBLIC int do_fork(message *msg) +{ + int r, proc, s, childproc, fullvm; + struct vmproc *vmp, *vmc; + + SANITYCHECK(SCL_FUNCTIONS); + + if(vm_isokendpt(msg->VMF_ENDPOINT, &proc) != OK) { + printf("VM: bogus endpoint VM_FORK %d\n", msg->VMF_ENDPOINT); + SANITYCHECK(SCL_FUNCTIONS); + return EINVAL; + } + + childproc = msg->VMF_SLOTNO; + if(childproc < 0 || childproc >= NR_PROCS) { + printf("VM: bogus slotno VM_FORK %d\n", msg->VMF_SLOTNO); + SANITYCHECK(SCL_FUNCTIONS); + return EINVAL; + } + + vmp = &vmproc[proc]; /* parent */ + vmc = &vmproc[childproc]; /* child */ + + if(vmp->vm_flags & VMF_HAS_DMA) { + printf("VM: %d has DMA memory and may not fork\n", msg->VMF_ENDPOINT); + return EINVAL; + } + + fullvm = vmp->vm_flags & VMF_HASPT; + + /* The child is basically a copy of the parent. */ + *vmc = *vmp; + vmc->vm_regions = NULL; + vmc->vm_endpoint = NONE; /* In case someone tries to use it. */ + +#if VMSTATS + vmc->vm_bytecopies = 0; +#endif + + if(fullvm) { + SANITYCHECK(SCL_DETAIL); + + if(pt_new(&vmc->vm_pt) != OK) { + printf("VM: fork: pt_new failed\n"); + return ENOMEM; + } + + SANITYCHECK(SCL_DETAIL); + + if(map_proc_copy(vmc, vmp) != OK) { + printf("VM: fork: map_proc_copy failed\n"); + pt_free(&vmc->vm_pt); + return(ENOMEM); + } + + if(vmp->vm_heap) { + vmc->vm_heap = map_region_lookup_tag(vmc, VRT_HEAP); + vm_assert(vmc->vm_heap); + } + + SANITYCHECK(SCL_DETAIL); + } else { + phys_bytes prog_bytes, parent_abs, child_abs; /* Intel only */ + phys_clicks prog_clicks, child_base; + + /* Determine how much memory to allocate. Only the data and stack + * need to be copied, because the text segment is either shared or + * of zero length. + */ + + prog_clicks = (phys_clicks) vmp->vm_arch.vm_seg[S].mem_len; + prog_clicks += (vmp->vm_arch.vm_seg[S].mem_vir - vmp->vm_arch.vm_seg[D].mem_vir); + prog_bytes = (phys_bytes) prog_clicks << CLICK_SHIFT; + if ( (child_base = ALLOC_MEM(prog_clicks, 0)) == NO_MEM) { + SANITYCHECK(SCL_FUNCTIONS); + return(ENOMEM); + } + + /* Create a copy of the parent's core image for the child. */ + child_abs = (phys_bytes) child_base << CLICK_SHIFT; + parent_abs = (phys_bytes) vmp->vm_arch.vm_seg[D].mem_phys << CLICK_SHIFT; + s = sys_abscopy(parent_abs, child_abs, prog_bytes); + if (s < 0) vm_panic("do_fork can't copy", s); + + /* A separate I&D child keeps the parents text segment. The data and stack + * segments must refer to the new copy. + */ + if (!(vmc->vm_flags & VMF_SEPARATE)) + vmc->vm_arch.vm_seg[T].mem_phys = child_base; + vmc->vm_arch.vm_seg[D].mem_phys = child_base; + vmc->vm_arch.vm_seg[S].mem_phys = vmc->vm_arch.vm_seg[D].mem_phys + + (vmp->vm_arch.vm_seg[S].mem_vir - vmp->vm_arch.vm_seg[D].mem_vir); + } + + /* Only inherit these flags. */ + vmc->vm_flags &= (VMF_INUSE|VMF_SEPARATE|VMF_HASPT); + + /* Tell kernel about the (now successful) FORK. */ + if((r=sys_fork(vmp->vm_endpoint, childproc, + &vmc->vm_endpoint, vmc->vm_arch.vm_seg, + fullvm ? PFF_VMINHIBIT : 0)) != OK) { + vm_panic("do_fork can't sys_fork", r); + } + + if(fullvm) { + if((r=pt_bind(&vmc->vm_pt, vmc)) != OK) + vm_panic("fork can't pt_bind", r); + } + + /* Inform caller of new child endpoint. */ + msg->VMF_CHILD_ENDPOINT = vmc->vm_endpoint; + + SANITYCHECK(SCL_FUNCTIONS); + return OK; +} + diff --git a/servers/vm/glo.h b/servers/vm/glo.h new file mode 100644 index 000000000..3d5153bd6 --- /dev/null +++ b/servers/vm/glo.h @@ -0,0 +1,29 @@ + +#include +#include +#include +#include + +#include "vm.h" +#include "vmproc.h" + +#if _MAIN +#undef EXTERN +#define EXTERN +#endif + +EXTERN struct vmproc vmproc[_NR_PROCS+1]; + +#if SANITYCHECKS +u32_t data1[200]; +#define CHECKADDR 0 +EXTERN long vm_sanitychecklevel; +#endif + +int verbosealloc; + +#define VMP_SYSTEM _NR_PROCS + +/* vm operation mode state and values */ +EXTERN long vm_paged; + diff --git a/servers/vm/i386/Makefile b/servers/vm/i386/Makefile new file mode 100644 index 000000000..805296e8c --- /dev/null +++ b/servers/vm/i386/Makefile @@ -0,0 +1,19 @@ + +include /etc/make.conf + +OBJ = vm.o pagetable.o arch_pagefaults.o util.o + +CPPFLAGS=-I../../../kernel/arch/$(ARCH)/include -I. +CFLAGS = $(CPROFILE) $(CPPFLAGS) + +all: $(OBJ) + +clean: + rm -f $(OBJ) + +depend: + mkdep "$(CC) -E $(CPPFLAGS)" *.c > .depend + +# Include generated dependencies. +include .depend + diff --git a/servers/vm/i386/arch_pagefaults.c b/servers/vm/i386/arch_pagefaults.c new file mode 100644 index 000000000..9ec324639 --- /dev/null +++ b/servers/vm/i386/arch_pagefaults.c @@ -0,0 +1,38 @@ + +#define _SYSTEM 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../glo.h" +#include "../proto.h" +#include "../util.h" + +/*===========================================================================* + * arch_handle_pagefaults * + *===========================================================================*/ +PUBLIC int arch_get_pagefault(who, addr, err) +endpoint_t *who; +vir_bytes *addr; +u32_t *err; +{ + return sys_vmctl_get_pagefault_i386(who, addr, err); +} + diff --git a/servers/vm/i386/arch_vmproc.h b/servers/vm/i386/arch_vmproc.h new file mode 100644 index 000000000..cab280383 --- /dev/null +++ b/servers/vm/i386/arch_vmproc.h @@ -0,0 +1,15 @@ + +#include + +struct vm_arch { + struct mem_map vm_seg[NR_LOCAL_SEGS]; /* text, data, stack */ + + /* vm_data_top points to top of data address space, as visible + * from user-space, in bytes. + * for segments processes this is the same + * as the top of vm_seg[S] segment. for paged processes this + * can be much higher (so more memory is available above the + * stack). + */ + u32_t vm_data_top; /* virtual process space in bytes */ +}; diff --git a/servers/vm/i386/memory.h b/servers/vm/i386/memory.h new file mode 100644 index 000000000..b770afff4 --- /dev/null +++ b/servers/vm/i386/memory.h @@ -0,0 +1,25 @@ +#include + +/* As visible from the user space process, where is the top of the + * stack (first non-stack byte), when in paged mode? + */ +#define VM_STACKTOP 0x80000000 + +/* And what is the highest addressable piece of memory, when in paged + * mode? Some data for kernel and stack are subtracted from this, the + * final results stored in bytes in arch.vm_data_top. + */ +#define VM_DATATOP 0xFFFFF000 + +#define SLAB_PAGESIZE I386_PAGE_SIZE +#define VM_PAGE_SIZE I386_PAGE_SIZE + +#define CLICKSPERPAGE (I386_PAGE_SIZE/CLICK_SIZE) + +/* Where is the kernel? */ +#define KERNEL_TEXT CLICK2ABS(vmproc[VMP_SYSTEM].vm_arch.vm_seg[T].mem_phys) +#define KERNEL_TEXT_LEN CLICK2ABS(vmproc[VMP_SYSTEM].vm_arch.vm_seg[T].mem_len) +#define KERNEL_DATA CLICK2ABS(vmproc[VMP_SYSTEM].vm_arch.vm_seg[D].mem_phys) +#define KERNEL_DATA_LEN CLICK2ABS(vmproc[VMP_SYSTEM].vm_arch.vm_seg[D].mem_len \ + + vmproc[VMP_SYSTEM].vm_arch.vm_seg[S].mem_len) + diff --git a/servers/vm/i386/pagefaults.h b/servers/vm/i386/pagefaults.h new file mode 100644 index 000000000..d9aab9deb --- /dev/null +++ b/servers/vm/i386/pagefaults.h @@ -0,0 +1,13 @@ + +#ifndef _PAGEFAULTS_H +#define _PAGEFAULTS_H 1 + +#include + +#define PFERR_NOPAGE(e) (!((e) & I386_VM_PFE_P)) +#define PFERR_PROT(e) (((e) & I386_VM_PFE_P)) +#define PFERR_WRITE(e) ((e) & I386_VM_PFE_W) +#define PFERR_READ(e) (!((e) & I386_VM_PFE_W)) + +#endif + diff --git a/servers/vm/i386/pagetable.c b/servers/vm/i386/pagetable.c new file mode 100644 index 000000000..e80a5e313 --- /dev/null +++ b/servers/vm/i386/pagetable.c @@ -0,0 +1,944 @@ + +#define _SYSTEM 1 + +#define VERBOSE 0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../proto.h" +#include "../glo.h" +#include "../util.h" +#include "../vm.h" +#include "../sanitycheck.h" + +#include "memory.h" + +/* Location in our virtual address space where we can map in + * any physical page we want. +*/ +static unsigned char *varmap = NULL; /* Our address space. */ +static u32_t varmap_loc; /* Our page table. */ + +/* Our process table entry. */ +struct vmproc *vmp = &vmproc[VM_PROC_NR]; + +/* Spare memory, ready to go after initialization, to avoid a + * circular dependency on allocating memory and writing it into VM's + * page table. + */ +#define SPAREPAGES 3 +static struct { + void *page; + u32_t phys; +} sparepages[SPAREPAGES]; + +/* Clicks must be pages, as + * - they must be page aligned to map them + * - they must be a multiple of the page size + * - it's inconvenient to have them bigger than pages, because we often want + * just one page + * May as well require them to be equal then. + */ +#if CLICK_SIZE != I386_PAGE_SIZE +#error CLICK_SIZE must be page size. +#endif + +/* Bytes of virtual address space one pde controls. */ +#define BYTESPERPDE (I386_VM_PT_ENTRIES * I386_PAGE_SIZE) + +/* Nevertheless, introduce these macros to make the code readable. */ +#define CLICK2PAGE(c) ((c) / CLICKSPERPAGE) + +#if SANITYCHECKS +#define PT_SANE(p) { pt_sanitycheck((p), __FILE__, __LINE__); SANITYCHECK(SCL_DETAIL); } +/*===========================================================================* + * pt_sanitycheck * + *===========================================================================*/ +PUBLIC void pt_sanitycheck(pt_t *pt, char *file, int line) +{ +/* Basic pt sanity check. */ + int i; + + MYASSERT(pt); + MYASSERT(pt->pt_dir); + MYASSERT(pt->pt_dir_phys); + + for(i = 0; i < I386_VM_DIR_ENTRIES; i++) { + if(pt->pt_pt[i]) { + MYASSERT(pt->pt_dir[i] & I386_VM_PRESENT); + } else { + MYASSERT(!(pt->pt_dir[i] & I386_VM_PRESENT)); + } + } +} +#else +#define PT_SANE(p) +#endif + +/*===========================================================================* + * aalloc * + *===========================================================================*/ +PRIVATE void *aalloc(size_t bytes) +{ +/* Page-aligned malloc(). only used if vm_allocpages can't be used. */ + u32_t b; + + b = (u32_t) malloc(I386_PAGE_SIZE + bytes); + if(!b) vm_panic("aalloc: out of memory", bytes); + b += I386_PAGE_SIZE - (b % I386_PAGE_SIZE); + + return (void *) b; +} + +/*===========================================================================* + * findhole * + *===========================================================================*/ +PRIVATE u32_t findhole(pt_t *pt, u32_t virbytes, u32_t vmin, u32_t vmax) +{ +/* Find a space in the virtual address space of pageteble 'pt', + * between page-aligned BYTE offsets vmin and vmax, to fit + * 'virbytes' in. Return byte offset. + * + * As a simple way to speed up the search a bit, we start searching + * after the location we found the previous hole, if that's in range. + * If that's not in range (or if that doesn't work), search the entire + * range (as well). try_restart controls whether we have to restart + * the search if it fails. (Just once of course.) + */ + u32_t freeneeded, freefound = 0, freestart = 0, curv; + int pde = 0, try_restart; + + /* Input sanity check. */ + vm_assert(vmin + virbytes >= vmin); + vm_assert(vmax >= vmin + virbytes); + vm_assert((virbytes % I386_PAGE_SIZE) == 0); + vm_assert((vmin % I386_PAGE_SIZE) == 0); + vm_assert((vmax % I386_PAGE_SIZE) == 0); + + /* How many pages do we need? */ + freeneeded = virbytes / I386_PAGE_SIZE; + + if(pt->pt_virtop >= vmin && pt->pt_virtop <= vmax - virbytes) { + curv = pt->pt_virtop; + try_restart = 1; + } else { + curv = vmin; + try_restart = 0; + } + + + /* Start looking for a consecutive block of free pages + * starting at vmin. + */ + for(freestart = curv; curv < vmax; ) { + int pte; + pde = I386_VM_PDE(curv); + pte = I386_VM_PTE(curv); + + if(!(pt->pt_dir[pde] & I386_VM_PRESENT)) { + int rempte; + rempte = I386_VM_PT_ENTRIES - pte; + freefound += rempte; + curv += rempte * I386_PAGE_SIZE; + } else { + if(pt->pt_pt[pde][pte] & I386_VM_PRESENT) { + freefound = 0; + freestart = curv + I386_PAGE_SIZE; + } else { + freefound++; + } + curv+=I386_PAGE_SIZE; + } + + if(freefound >= freeneeded) { + u32_t v; + v = freestart; + vm_assert(v != NO_MEM); + vm_assert(v >= vmin); + vm_assert(v < vmax); + + /* Next time, start looking here. */ + pt->pt_virtop = v + virbytes; + + return v; + } + + if(curv >= vmax && try_restart) { + curv = vmin; + try_restart = 0; + } + } + + printf("VM: out of virtual address space in a process\n"); + + return NO_MEM; +} + +/*===========================================================================* + * vm_freepages * + *===========================================================================*/ +PRIVATE void vm_freepages(vir_bytes vir, vir_bytes phys, int pages, int reason) +{ + vm_assert(reason >= 0 && reason < VMP_CATEGORIES); + if(vir >= vmp->vm_stacktop) { + vm_assert(!(vir % I386_PAGE_SIZE)); + vm_assert(!(phys % I386_PAGE_SIZE)); + FREE_MEM(ABS2CLICK(phys), pages); + if(pt_writemap(&vmp->vm_pt, + vir + CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys), + 0, pages*I386_PAGE_SIZE, 0, WMF_OVERWRITE) != OK) + vm_panic("vm_freepages: pt_writemap failed", + NO_NUM); + } else { + printf("VM: vm_freepages not freeing VM heap pages (%d)\n", + pages); + } +} + +/*===========================================================================* + * vm_getsparepage * + *===========================================================================*/ +PRIVATE void *vm_getsparepage(u32_t *phys) +{ + int s; + for(s = 0; s < SPAREPAGES; s++) { + if(sparepages[s].page) { + void *sp; + sp = sparepages[s].page; + *phys = sparepages[s].phys; + sparepages[s].page = NULL; + return sp; + } + } + vm_panic("VM: out of spare pages", NO_NUM); + return NULL; +} + +/*===========================================================================* + * vm_checkspares * + *===========================================================================*/ +PRIVATE void *vm_checkspares(void) +{ + int s, n = 0; + static int total = 0, worst = 0; + for(s = 0; s < SPAREPAGES; s++) + if(!sparepages[s].page) { + n++; + sparepages[s].page = vm_allocpages(&sparepages[s].phys, 1, + VMP_SPARE); + } + if(worst < n) worst = n; + total += n; +#if 0 + if(n > 0) + printf("VM: made %d spares, total %d, worst %d\n", n, total, worst); +#endif + return NULL; +} + +/*===========================================================================* + * vm_allocpages * + *===========================================================================*/ +PUBLIC void *vm_allocpages(phys_bytes *phys, int pages, int reason) +{ +/* Allocate a number of pages for use by VM itself. */ + phys_bytes newpage; + vir_bytes loc; + pt_t *pt; + int r; + vir_bytes bytes = pages * I386_PAGE_SIZE; + static int level = 0; +#define MAXDEPTH 10 + static int reasons[MAXDEPTH]; + + pt = &vmp->vm_pt; + vm_assert(reason >= 0 && reason < VMP_CATEGORIES); + vm_assert(pages > 0); + + reasons[level++] = reason; + + vm_assert(level >= 1); + vm_assert(level <= 2); + + if(level > 1 || !(vmp->vm_flags & VMF_HASPT)) { + int r; + void *s; + vm_assert(pages == 1); + s=vm_getsparepage(phys); + level--; + return s; + } + + /* VM does have a pagetable, so get a page and map it in there. + * Where in our virtual address space can we put it? + */ + loc = findhole(pt, I386_PAGE_SIZE * pages, + CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys) + vmp->vm_stacktop, + vmp->vm_arch.vm_data_top); + if(loc == NO_MEM) { + level--; + return NULL; + } + + /* Allocate 'pages' pages of memory for use by VM. As VM + * is trusted, we don't have to pre-clear it. + */ + if((newpage = ALLOC_MEM(CLICKSPERPAGE * pages, 0)) == NO_MEM) { + level--; + return NULL; + } + + *phys = CLICK2ABS(newpage); + + /* Map this page into our address space. */ + if((r=pt_writemap(pt, loc, *phys, bytes, + I386_VM_PRESENT | I386_VM_USER | I386_VM_WRITE, 0)) != OK) { + FREE_MEM(newpage, CLICKSPERPAGE * pages / I386_PAGE_SIZE); + return NULL; + } + + level--; + + /* Return user-space-ready pointer to it. */ + return (void *) (loc - CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys)); +} + +/*===========================================================================* + * pt_ptalloc * + *===========================================================================*/ +PRIVATE int pt_ptalloc(pt_t *pt, int pde, u32_t flags) +{ +/* Allocate a page table and write its address into the page directory. */ + int i; + u32_t pt_phys; + + /* Argument must make sense. */ + vm_assert(pde >= 0 && pde < I386_VM_DIR_ENTRIES); + vm_assert(!(flags & ~(PTF_ALLFLAGS | PTF_MAPALLOC))); + + /* We don't expect to overwrite page directory entry, nor + * storage for the page table. + */ + vm_assert(!(pt->pt_dir[pde] & I386_VM_PRESENT)); + vm_assert(!pt->pt_pt[pde]); + PT_SANE(pt); + + /* Get storage for the page table. */ + if(!(pt->pt_pt[pde] = vm_allocpages(&pt_phys, 1, VMP_PAGETABLE))) + return ENOMEM; + + for(i = 0; i < I386_VM_PT_ENTRIES; i++) + pt->pt_pt[pde][i] = 0; /* Empty entry. */ + + /* Make page directory entry. + * The PDE is always 'present,' 'writable,' and 'user accessible,' + * relying on the PTE for protection. + */ + pt->pt_dir[pde] = (pt_phys & I386_VM_ADDR_MASK) | flags + | I386_VM_PRESENT | I386_VM_USER | I386_VM_WRITE; + vm_assert(flags & I386_VM_PRESENT); + PT_SANE(pt); + + return OK; +} + +/*===========================================================================* + * pt_writemap * + *===========================================================================*/ +PUBLIC int pt_writemap(pt_t *pt, vir_bytes v, phys_bytes physaddr, + size_t bytes, u32_t flags, u32_t writemapflags) +{ +/* Write mapping into page table. Allocate a new page table if necessary. */ +/* Page directory and table entries for this virtual address. */ + int p, pages, pde; + SANITYCHECK(SCL_FUNCTIONS); + + vm_assert(!(bytes % I386_PAGE_SIZE)); + vm_assert(!(flags & ~(PTF_ALLFLAGS | PTF_MAPALLOC))); + + pages = bytes / I386_PAGE_SIZE; + +#if SANITYCHECKS + if(physaddr && !(flags & I386_VM_PRESENT)) { + vm_panic("pt_writemap: writing dir with !P\n", NO_NUM); + } + if(!physaddr && flags) { + vm_panic("pt_writemap: writing 0 with flags\n", NO_NUM); + } +#endif + + PT_SANE(pt); + + /* First make sure all the necessary page tables are allocated, + * before we start writing in any of them, because it's a pain + * to undo our work properly. Walk the range in page-directory-entry + * sized leaps. + */ + for(pde = I386_VM_PDE(v); pde <= I386_VM_PDE(v + I386_PAGE_SIZE * pages); pde++) { + vm_assert(pde >= 0 && pde < I386_VM_DIR_ENTRIES); + if(!(pt->pt_dir[pde] & I386_VM_PRESENT)) { + int r; + vm_assert(!pt->pt_dir[pde]); + if((r=pt_ptalloc(pt, pde, flags)) != OK) { + /* Couldn't do (complete) mapping. + * Don't bother freeing any previously + * allocated page tables, they're + * still writable, don't point to nonsense, + * and pt_ptalloc leaves the directory + * and other data in a consistent state. + */ + return r; + } + } + vm_assert(pt->pt_dir[pde] & I386_VM_PRESENT); + } + + PT_SANE(pt); + + /* Now write in them. */ + for(p = 0; p < pages; p++) { + int pde = I386_VM_PDE(v); + int pte = I386_VM_PTE(v); + PT_SANE(pt); + + vm_assert(!(v % I386_PAGE_SIZE)); + vm_assert(pte >= 0 && pte < I386_VM_PT_ENTRIES); + vm_assert(pde >= 0 && pde < I386_VM_DIR_ENTRIES); + + /* Page table has to be there. */ + vm_assert(pt->pt_dir[pde] & I386_VM_PRESENT); + + /* Make sure page directory entry for this page table + * is marked present and page table entry is available. + */ + vm_assert((pt->pt_dir[pde] & I386_VM_PRESENT) && pt->pt_pt[pde]); + + PT_SANE(pt); +#if SANITYCHECKS + /* We don't expect to overwrite a page. */ + if(!(writemapflags & WMF_OVERWRITE)) + vm_assert(!(pt->pt_pt[pde][pte] & I386_VM_PRESENT)); +#endif + + /* Write pagetable entry. */ + pt->pt_pt[pde][pte] = (physaddr & I386_VM_ADDR_MASK) | flags; + + physaddr += I386_PAGE_SIZE; + v += I386_PAGE_SIZE; + PT_SANE(pt); + } + SANITYCHECK(SCL_FUNCTIONS); + PT_SANE(pt); + + return OK; +} + +/*===========================================================================* + * pt_new * + *===========================================================================*/ +PUBLIC int pt_new(pt_t *pt) +{ +/* Allocate a pagetable root. On i386, allocate a page-aligned page directory + * and set them to 0 (indicating no page tables are allocated). Lookup + * its physical address as we'll need that in the future. Verify it's + * page-aligned. + */ + int i; + + if(!(pt->pt_dir = vm_allocpages(&pt->pt_dir_phys, 1, VMP_PAGEDIR))) { + return ENOMEM; + } + + for(i = 0; i < I386_VM_DIR_ENTRIES; i++) { + pt->pt_dir[i] = 0; /* invalid entry (I386_VM_PRESENT bit = 0) */ + pt->pt_pt[i] = NULL; + } + + /* Where to start looking for free virtual address space? */ + pt->pt_virtop = VM_STACKTOP + + CLICK2ABS(vmproc[VMP_SYSTEM].vm_arch.vm_seg[D].mem_phys); + + return OK; +} + + + +/*===========================================================================* + * pt_allocmap * + *===========================================================================*/ +PUBLIC int pt_allocmap(pt_t *pt, vir_bytes v_min, vir_bytes v_max, + size_t bytes, u32_t pageflags, u32_t memflags, vir_bytes *v_final) +{ +/* Allocate new memory, and map it into the page table. */ + u32_t newpage; + u32_t v; + int r; + + /* Input sanity check. */ + PT_SANE(pt); + vm_assert(!(pageflags & ~PTF_ALLFLAGS)); + + /* Valid no-op. */ + if(bytes == 0) return OK; + + /* Round no. of bytes up to a page. */ + if(bytes % I386_PAGE_SIZE) { + bytes += I386_PAGE_SIZE - (bytes % I386_PAGE_SIZE); + } + + /* Special case; if v_max is 0, the request is to map the memory + * into v_min at exactly that location. We raise v_max as necessary, + * so the check to see if the virtual space is free does happen. + */ + if(v_max == 0) { + v_max = v_min + bytes; + + /* Sanity check. */ + if(v_max < v_min) { + printf("pt_allocmap: v_min 0x%lx and bytes 0x%lx\n", + v_min, bytes); + return ENOMEM; + } + } + + /* Basic sanity check. */ + if(v_max < v_min) { + printf("pt_allocmap: v_min 0x%lx, v_max 0x%lx\n", v_min, v_max); + return ENOMEM; + } + + /* v_max itself may not be used. Bytes may be 0. */ + if(v_max < v_min + bytes) { + printf("pt_allocmap: v_min 0x%lx, bytes 0x%lx, v_max 0x%lx\n", + v_min, bytes, v_max); + return ENOMEM; + } + + /* Find where to fit this into the virtual address space. */ + v = findhole(pt, bytes, v_min, v_max); + if(v == NO_MEM) { + printf("pt_allocmap: no hole found to map 0x%lx bytes into\n", + bytes); + return ENOSPC; + } + + vm_assert(!(v % I386_PAGE_SIZE)); + + if(v_final) *v_final = v; + + /* Memory is currently always allocated contiguously physically, + * but if that were to change, note the setting of + * PAF_CONTIG in memflags. + */ + + newpage = ALLOC_MEM(CLICKSPERPAGE * bytes / I386_PAGE_SIZE, memflags); + if(newpage == NO_MEM) { + printf("pt_allocmap: out of memory\n"); + return ENOMEM; + } + + /* Write into the page table. */ + if((r=pt_writemap(pt, v, CLICK2ABS(newpage), bytes, + pageflags | PTF_MAPALLOC, 0)) != OK) { + FREE_MEM(newpage, CLICKSPERPAGE * bytes / I386_PAGE_SIZE); + return r; + } + + /* Sanity check result. */ + PT_SANE(pt); + + return OK; +} + +/*===========================================================================* + * raw_readmap * + *===========================================================================*/ +PRIVATE int raw_readmap(phys_bytes root, u32_t v, u32_t *phys, u32_t *flags) +{ + u32_t dir[I386_VM_DIR_ENTRIES]; + u32_t tab[I386_VM_PT_ENTRIES]; + int pde, pte, r; + + /* Sanity check. */ + vm_assert((root % I386_PAGE_SIZE) == 0); + vm_assert((v % I386_PAGE_SIZE) == 0); + + /* Get entry in page directory. */ + pde = I386_VM_PDE(v); + if((r=sys_physcopy(SYSTEM, PHYS_SEG, root, + SELF, VM_D, (phys_bytes) dir, sizeof(dir))) != OK) { + printf("VM: raw_readmap: sys_physcopy failed (dir) (%d)\n", r); + return EFAULT; + } + + if(!(dir[pde] & I386_VM_PRESENT)) { + printf("raw_readmap: 0x%lx: pde %d not present: 0x%lx\n", + v, pde, dir[pde]); + return EFAULT; + } + + /* Get entry in page table. */ + if((r=sys_physcopy(SYSTEM, PHYS_SEG, I386_VM_PFA(dir[pde]), + SELF, VM_D, (vir_bytes) tab, sizeof(tab))) != OK) { + printf("VM: raw_readmap: sys_physcopy failed (tab) (r)\n"); + return EFAULT; + } + pte = I386_VM_PTE(v); + if(!(tab[pte] & I386_VM_PRESENT)) { + printf("raw_readmap: 0x%lx: pde %d not present: 0x%lx\n", + v, pte, tab[pte]); + return EFAULT; + } + + /* Get address and flags. */ + *phys = I386_VM_PFA(tab[pte]); + *flags = tab[pte] & PTF_ALLFLAGS; + + return OK; +} + +/*===========================================================================* + * pt_init * + *===========================================================================*/ +PUBLIC void pt_init(void) +{ +/* By default, the kernel gives us a data segment with pre-allocated + * memory that then can't grow. We want to be able to allocate memory + * dynamically, however. So here we copy the part of the page table + * that's ours, so we get a private page table. Then we increase the + * hardware segment size so we can allocate memory above our stack. + */ + u32_t my_cr3; + pt_t *newpt; + int s, r; + vir_bytes v; + phys_bytes lo, hi; + vir_bytes extra_clicks; + + /* Retrieve current CR3 - shared page table. */ + if((r=sys_vmctl_get_cr3_i386(SELF, &my_cr3)) != OK) + vm_panic("pt_init: sys_vmctl_get_cr3_i386 failed", r); + + /* Shorthand. */ + newpt = &vmp->vm_pt; + + /* Get ourselves a spare page. */ + for(s = 0; s < SPAREPAGES; s++) { + if(!(sparepages[s].page = aalloc(I386_PAGE_SIZE))) + vm_panic("pt_init: aalloc for spare failed", NO_NUM); + if((r=sys_umap(SELF, VM_D, (vir_bytes) sparepages[s].page, + I386_PAGE_SIZE, &sparepages[s].phys)) != OK) + vm_panic("pt_init: sys_umap failed", r); + } + + /* Make new page table for ourselves, partly copied + * from the current one. + */ + if(pt_new(newpt) != OK) + vm_panic("pt_init: pt_new failed", NO_NUM); + + /* Initial (current) range of our virtual address space. */ + lo = CLICK2ABS(vmp->vm_arch.vm_seg[T].mem_phys); + hi = CLICK2ABS(vmp->vm_arch.vm_seg[S].mem_phys + + vmp->vm_arch.vm_seg[S].mem_len); + + /* Copy the mappings from the shared page table to our private one. */ + for(v = lo; v < hi; v += I386_PAGE_SIZE) { + phys_bytes addr; + u32_t flags; + if(raw_readmap(my_cr3, v, &addr, &flags) != OK) + vm_panic("pt_init: raw_readmap failed", NO_NUM); + if(pt_writemap(newpt, v, addr, I386_PAGE_SIZE, flags, 0) != OK) + vm_panic("pt_init: pt_writemap failed", NO_NUM); + } + + /* Map in kernel. */ + if(pt_mapkernel(newpt) != OK) + vm_panic("pt_init: pt_mapkernel failed", NO_NUM); + + /* Give our process the new, copied, private page table. */ + pt_bind(newpt, vmp); + + /* Increase our hardware data segment to create virtual address + * space above our stack. We want to increase it to VM_DATATOP, + * like regular processes have. + */ + extra_clicks = ABS2CLICK(VM_DATATOP - hi); + vmp->vm_arch.vm_seg[S].mem_len += extra_clicks; + + /* We pretend to the kernel we have a huge stack segment to + * increase our data segment. + */ + vmp->vm_arch.vm_data_top = + (vmp->vm_arch.vm_seg[S].mem_vir + + vmp->vm_arch.vm_seg[S].mem_len) << CLICK_SHIFT; + + if((s=sys_newmap(VM_PROC_NR, vmp->vm_arch.vm_seg)) != OK) + vm_panic("VM: pt_init: sys_newmap failed", s); + + /* Back to reality - this is where the stack actually is. */ + vmp->vm_arch.vm_seg[S].mem_len -= extra_clicks; + + /* Where our free virtual address space starts. + * This is only a hint to the VM system. + */ + newpt->pt_virtop = (vmp->vm_arch.vm_seg[S].mem_vir + + vmp->vm_arch.vm_seg[S].mem_len) << CLICK_SHIFT; + + /* Let other functions know VM now has a private page table. */ + vmp->vm_flags |= VMF_HASPT; + + /* Reserve a page in our virtual address space that we + * can use to map in arbitrary physical pages. + */ + varmap_loc = findhole(newpt, I386_PAGE_SIZE, + CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys) + vmp->vm_stacktop, + vmp->vm_arch.vm_data_top); + if(varmap_loc == NO_MEM) { + vm_panic("no virt addr for vm mappings", NO_NUM); + } + varmap = (unsigned char *) (varmap_loc - + CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys)); + + /* All OK. */ + return; +} + +/*===========================================================================* + * pt_bind * + *===========================================================================*/ +PUBLIC int pt_bind(pt_t *pt, struct vmproc *who) +{ + /* Basic sanity checks. */ + vm_assert(who); + vm_assert(who->vm_flags & VMF_INUSE); + if(pt) PT_SANE(pt); + + /* Tell kernel about new page table root. */ + return sys_vmctl(who->vm_endpoint, VMCTL_I386_SETCR3, + pt ? pt->pt_dir_phys : 0); +} + +/*===========================================================================* + * pt_free * + *===========================================================================*/ +PUBLIC void pt_free(pt_t *pt) +{ +/* Free memory associated with this pagetable. */ + int i; + + PT_SANE(pt); + + for(i = 0; i < I386_VM_DIR_ENTRIES; i++) { + int p; + if(pt->pt_pt[i]) { + for(p = 0; p < I386_VM_PT_ENTRIES; p++) { + if((pt->pt_pt[i][p] & (PTF_MAPALLOC | I386_VM_PRESENT)) + == (PTF_MAPALLOC | I386_VM_PRESENT)) { + u32_t pa = I386_VM_PFA(pt->pt_pt[i][p]); + FREE_MEM(ABS2CLICK(pa), CLICKSPERPAGE); + } + } + vm_freepages((vir_bytes) pt->pt_pt[i], + I386_VM_PFA(pt->pt_dir[i]), 1, VMP_PAGETABLE); + } + } + + vm_freepages((vir_bytes) pt->pt_dir, pt->pt_dir_phys, 1, VMP_PAGEDIR); + + return; +} + +/*===========================================================================* + * pt_mapkernel * + *===========================================================================*/ +PUBLIC int pt_mapkernel(pt_t *pt) +{ + int r; + + /* Any i386 page table needs to map in the kernel address space. */ + vm_assert(vmproc[VMP_SYSTEM].vm_flags & VMF_INUSE); + + /* Map in text. flags: don't write, supervisor only */ + if((r=pt_writemap(pt, KERNEL_TEXT, KERNEL_TEXT, KERNEL_TEXT_LEN, + I386_VM_PRESENT | I386_VM_USER | I386_VM_WRITE, 0)) != OK) + return r; + + /* Map in data. flags: read-write, supervisor only */ + if((r=pt_writemap(pt, KERNEL_DATA, KERNEL_DATA, KERNEL_DATA_LEN, + I386_VM_PRESENT | I386_VM_USER | I386_VM_WRITE, 0)) != OK) + return r; + + return OK; +} + +/*===========================================================================* + * pt_freerange * + *===========================================================================*/ +PUBLIC void pt_freerange(pt_t *pt, vir_bytes low, vir_bytes high) +{ +/* Free memory allocated by pagetable functions in this range. */ + int pde; + u32_t v; + + PT_SANE(pt); + + for(v = low; v < high; v += I386_PAGE_SIZE) { + int pte; + pde = I386_VM_PDE(v); + pte = I386_VM_PTE(v); + if(!(pt->pt_dir[pde] & I386_VM_PRESENT)) + continue; + if((pt->pt_pt[pde][pte] & (PTF_MAPALLOC | I386_VM_PRESENT)) + == (PTF_MAPALLOC | I386_VM_PRESENT)) { + u32_t pa = I386_VM_PFA(pt->pt_pt[pde][pte]); + FREE_MEM(ABS2CLICK(pa), CLICKSPERPAGE); + pt->pt_pt[pde][pte] = 0; + } + } + + PT_SANE(pt); + + return; +} + +/*===========================================================================* + * pt_cycle * + *===========================================================================*/ +PUBLIC void pt_cycle(void) +{ + vm_checkspares(); +} + +/*===========================================================================* + * pt_copy * + *===========================================================================*/ +PUBLIC int pt_copy(pt_t *src, pt_t *dst) +{ + int i, r; + + SANITYCHECK(SCL_FUNCTIONS); + PT_SANE(src); + + if((r=pt_new(dst)) != OK) + return r; + + for(i = 0; i < I386_VM_DIR_ENTRIES; i++) { + int p; + if(!(src->pt_dir[i] & I386_VM_PRESENT)) + continue; + for(p = 0; p < I386_VM_PT_ENTRIES; p++) { + u32_t v = i * I386_VM_PT_ENTRIES * I386_PAGE_SIZE + + p * I386_PAGE_SIZE; + u32_t pa1, pa2, flags; + if(!(src->pt_pt[i][p] & I386_VM_PRESENT)) + continue; +#if 0 + if((dst->pt_pt[i] && + (dst->pt_pt[i][p] & I386_VM_PRESENT))) + continue; +#endif + flags = src->pt_pt[i][p] & (PTF_WRITE | PTF_USER); + flags |= I386_VM_PRESENT; + pa1 = I386_VM_PFA(src->pt_pt[i][p]); + if(PTF_MAPALLOC & src->pt_pt[i][p]) { + PT_SANE(dst); + if(pt_allocmap(dst, v, 0, + I386_PAGE_SIZE, flags, 0, NULL) != OK) { + pt_free(dst); + return ENOMEM; + } + pa2 = I386_VM_PFA(dst->pt_pt[i][p]); + sys_abscopy(pa1, pa2, I386_PAGE_SIZE); + } else { + PT_SANE(dst); + if(pt_writemap(dst, v, pa1, I386_PAGE_SIZE, flags, 0) != OK) { + pt_free(dst); + return ENOMEM; + } + } + } + } + + PT_SANE(src); + PT_SANE(dst); + SANITYCHECK(SCL_FUNCTIONS); + + return OK; +} + +#define PHYS_MAP(a, o) \ +{ int r; \ + vm_assert(varmap); \ + (o) = (a) % I386_PAGE_SIZE; \ + r = pt_writemap(&vmp->vm_pt, varmap_loc, (a) - (o), I386_PAGE_SIZE, \ + I386_VM_PRESENT | I386_VM_USER | I386_VM_WRITE, 0); \ + if(r != OK) \ + vm_panic("PHYS_MAP: pt_writemap failed", NO_NUM); \ + /* pt_bind() flushes TLB. */ \ + pt_bind(&vmp->vm_pt, vmp); \ +} + +#define PHYSMAGIC 0x7b9a0590 + +#define PHYS_UNMAP if(OK != pt_writemap(&vmp->vm_pt, varmap_loc, 0, \ + I386_PAGE_SIZE, 0, WMF_OVERWRITE)) { \ + vm_panic("PHYS_UNMAP: pt_writemap failed", NO_NUM); } + +#define PHYS_VAL(o) (* (phys_bytes *) (varmap + (o))) + +/*===========================================================================* + * phys_writeaddr * + *===========================================================================*/ +PUBLIC void phys_writeaddr(phys_bytes addr, phys_bytes v1, phys_bytes v2) +{ + phys_bytes offset; + + SANITYCHECK(SCL_DETAIL); + PHYS_MAP(addr, offset); + PHYS_VAL(offset) = v1; + PHYS_VAL(offset + sizeof(phys_bytes)) = v2; +#if SANITYCHECKS + PHYS_VAL(offset + 2*sizeof(phys_bytes)) = PHYSMAGIC; +#endif + PHYS_UNMAP; + SANITYCHECK(SCL_DETAIL); +} + +/*===========================================================================* + * phys_readaddr * + *===========================================================================*/ +PUBLIC void phys_readaddr(phys_bytes addr, phys_bytes *v1, phys_bytes *v2) +{ + phys_bytes offset; + + SANITYCHECK(SCL_DETAIL); + PHYS_MAP(addr, offset); + *v1 = PHYS_VAL(offset); + *v2 = PHYS_VAL(offset + sizeof(phys_bytes)); +#if SANITYCHECKS + vm_assert(PHYS_VAL(offset + 2*sizeof(phys_bytes)) == PHYSMAGIC); +#endif + PHYS_UNMAP; + SANITYCHECK(SCL_DETAIL); +} diff --git a/servers/vm/i386/pagetable.h b/servers/vm/i386/pagetable.h new file mode 100644 index 000000000..e4934c72e --- /dev/null +++ b/servers/vm/i386/pagetable.h @@ -0,0 +1,37 @@ + +#ifndef _PAGETABLE_H +#define _PAGETABLE_H 1 + +#include +#include + +/* An i386 pagetable. */ +typedef struct { + /* Directory entries in VM addr space - root of page table. */ + u32_t *pt_dir; /* page aligned (I386_VM_DIR_ENTRIES) */ + u32_t pt_dir_phys; /* physical address of pt_dir */ + + /* Pointers to page tables in VM address space. */ + u32_t *pt_pt[I386_VM_DIR_ENTRIES]; + + /* When looking for a hole in virtual address space, start + * looking here. This is in linear addresses, i.e., + * not as the process sees it but the position in the page + * page table. This is just a hint. + */ + u32_t pt_virtop; +} pt_t; + +/* Mapping flags. */ +#define PTF_WRITE I386_VM_WRITE +#define PTF_PRESENT I386_VM_PRESENT +#define PTF_USER I386_VM_USER +#define PTF_MAPALLOC I386_VM_PTAVAIL1 /* Page allocated by pt code. */ + +/* For arch-specific PT routines to check if no bits outside + * the regular flags are set. + */ +#define PTF_ALLFLAGS (PTF_WRITE|PTF_PRESENT|PTF_USER) + +#endif + diff --git a/servers/vm/i386/util.s b/servers/vm/i386/util.s new file mode 100644 index 000000000..7b3122731 --- /dev/null +++ b/servers/vm/i386/util.s @@ -0,0 +1,23 @@ + +.sect .text; .sect .rom; .sect .data; .sect .bss + +.define _i386_invlpg + +.sect .text + +!*===========================================================================* +!* i386_invlpg * +!*===========================================================================* +! PUBLIC void i386_invlpg(u32_t addr) +! Tell the processor to invalidate a tlb entry at virtual address addr. +_i386_invlpg: + push ebp + mov ebp, esp + push eax + + mov eax, 8(ebp) + invlpg eax + + pop eax + pop ebp + ret diff --git a/servers/vm/i386/vm.c b/servers/vm/i386/vm.c new file mode 100644 index 000000000..1f55874cf --- /dev/null +++ b/servers/vm/i386/vm.c @@ -0,0 +1,115 @@ + +#define _SYSTEM 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "../proto.h" +#include "../vm.h" +#include "../util.h" + +#include "memory.h" + +#define PAGE_SIZE 4096 +#define PAGE_DIR_SIZE (1024*PAGE_SIZE) +#define PAGE_TABLE_COVER (1024*PAGE_SIZE) +/*=========================================================================* + * arch_init_vm * + *=========================================================================*/ +PUBLIC void arch_init_vm(mem_chunks) +struct memory mem_chunks[NR_MEMS]; +{ + phys_bytes high, bytes; + phys_clicks clicks, base_click; + unsigned pages; + int i, r; + + /* Compute the highest memory location */ + high= 0; + for (i= 0; i high) + high= mem_chunks[i].base + mem_chunks[i].size; + } + + high <<= CLICK_SHIFT; +#if VERBOSE_VM + printf("do_x86_vm: found high 0x%x\n", high); +#endif + + /* Rounding up */ + high= (high-1+PAGE_DIR_SIZE) & ~(PAGE_DIR_SIZE-1); + + /* The number of pages we need is one for the page directory, enough + * page tables to cover the memory, and one page for alignement. + */ + pages= 1 + (high + PAGE_TABLE_COVER-1)/PAGE_TABLE_COVER + 1; + bytes= pages*PAGE_SIZE; + clicks= (bytes + CLICK_SIZE-1) >> CLICK_SHIFT; + +#if VERBOSE_VM + printf("do_x86_vm: need %d pages\n", pages); + printf("do_x86_vm: need %d bytes\n", bytes); + printf("do_x86_vm: need %d clicks\n", clicks); +#endif + + for (i= 0; i= NR_MEMS) + panic("VM", "not enough memory for VM page tables?", NO_NUM); + base_click= mem_chunks[i].base; + mem_chunks[i].base += clicks; + mem_chunks[i].size -= clicks; + +#if VERBOSE_VM + printf("do_x86_vm: using 0x%x clicks @ 0x%x\n", clicks, base_click); +#endif + r= sys_vm_setbuf(base_click << CLICK_SHIFT, clicks << CLICK_SHIFT, + high); + if (r != 0) + printf("do_x86_vm: sys_vm_setbuf failed: %d\n", r); + +} + +/*===========================================================================* + * arch_map2vir * + *===========================================================================*/ +PUBLIC vir_bytes arch_map2vir(struct vmproc *vmp, vir_bytes addr) +{ + vir_bytes bottom = CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys); + + vm_assert(bottom <= addr); + + return addr - bottom; +} + +/*===========================================================================* + * arch_vir2map * + *===========================================================================*/ +PUBLIC vir_bytes arch_vir2map(struct vmproc *vmp, vir_bytes addr) +{ + vir_bytes bottom = CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys); + + return addr + bottom; +} diff --git a/servers/vm/main.c b/servers/vm/main.c new file mode 100644 index 000000000..02bf87b7c --- /dev/null +++ b/servers/vm/main.c @@ -0,0 +1,274 @@ + +#define _SYSTEM 1 + +#define VERBOSE 0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define _MAIN 1 +#include "glo.h" +#include "proto.h" +#include "util.h" +#include "vm.h" +#include "sanitycheck.h" + +#include +#include "../../kernel/const.h" +#include "../../kernel/config.h" +#include "../../kernel/proc.h" + +/* Table of calls and a macro to test for being in range. */ +struct { + endpoint_t vmc_caller; /* Process that does this, or ANY */ + int (*vmc_func)(message *); /* Call handles message. */ + char *vmc_name; /* Human-readable string. */ +} vm_calls[VM_NCALLS]; + +/* Macro to verify call range and map 'high' range to 'base' range + * (starting at 0) in one. Evaluates to zero-based call number if call + * number is valid, returns -1 otherwise. + */ +#define CALLNUMBER(c) (((c) >= VM_RQ_BASE && \ + (c) < VM_RQ_BASE + ELEMENTS(vm_calls)) ? \ + ((c) - VM_RQ_BASE) : -1) + +FORWARD _PROTOTYPE(void vm_init, (void)); + +#if SANITYCHECKS +extern int kputc_use_private_grants; +#endif + +/*===========================================================================* + * main * + *===========================================================================*/ +PUBLIC int main(void) +{ + message msg; + int result, who_e; + +#if SANITYCHECKS + memcpy(data1, CHECKADDR, sizeof(data1)); +#endif + SANITYCHECK(SCL_TOP); + + vm_paged = 0; + env_parse("vm_paged", "d", 0, &vm_paged, 0, 1); +#if SANITYCHECKS + env_parse("vm_sanitychecklevel", "d", 0, &vm_sanitychecklevel, 0, SCL_MAX); +#endif + + SANITYCHECK(SCL_TOP); + + vm_init(); + SANITYCHECK(SCL_TOP); + + /* This is VM's main loop. */ + while (TRUE) { + int r, c; + + SANITYCHECK(SCL_TOP); + pt_cycle(); /* pagetable code wants to be called */ +#if SANITYCHECKS + slabstats(); +#endif + SANITYCHECK(SCL_DETAIL); + + if ((r=receive(ANY, &msg)) != OK) + vm_panic("receive() error", r); + + if(msg.m_source == LOG_PROC_NR || + msg.m_source == TTY_PROC_NR) + continue; + + SANITYCHECK(SCL_DETAIL); + + if(msg.m_type & NOTIFY_MESSAGE) { + switch(msg.m_source) { + case SYSTEM: + /* Kernel wants to have memory ranges + * verified. + */ + handle_memory(); + break; + case PM_PROC_NR: + /* PM sends a notify() on shutdown, which + * is OK and we ignore. + */ + break; + case HARDWARE: + /* This indicates a page fault has happened, + * which we have to handle. + */ + handle_pagefaults(); + break; + default: + /* No-one else should send us notifies. */ + printf("VM: ignoring notify() from %d\n", + msg.m_source); + break; + } + continue; + } + who_e = msg.m_source; + c = msg.m_type - VM_RQ_BASE; + result = ENOSYS; /* Out of range or restricted calls return this. */ + if((c=CALLNUMBER(msg.m_type)) < 0 || !vm_calls[c].vmc_func) { + printf("VM: out of range or missing callnr %d from %d\n", + msg.m_type, msg.m_source); + } else if(vm_calls[c].vmc_caller != ANY && + vm_calls[c].vmc_caller != msg.m_source) { + printf("VM: restricted callnr %d (%s) from %d instead of %d\n", + c, + vm_calls[c].vmc_name, msg.m_source, + vm_calls[c].vmc_caller); + } else { + SANITYCHECK(SCL_FUNCTIONS); + result = vm_calls[c].vmc_func(&msg); + SANITYCHECK(SCL_FUNCTIONS); + } + + /* Send reply message, unless the return code is SUSPEND, + * which is a pseudo-result suppressing the reply message. + */ + if(result != SUSPEND) { + SANITYCHECK(SCL_DETAIL); + msg.m_type = result; + if((r=send(who_e, &msg)) != OK) { + printf("VM: couldn't send %d to %d (err %d)\n", + msg.m_type, who_e, r); + vm_panic("send() error", NO_NUM); + } + SANITYCHECK(SCL_DETAIL); + } + SANITYCHECK(SCL_DETAIL); + } + return(OK); +} + +/*===========================================================================* + * vm_init * + *===========================================================================*/ +PRIVATE void vm_init(void) +{ + int s; + struct memory mem_chunks[NR_MEMS]; + struct boot_image image[NR_BOOT_PROCS]; + struct boot_image *ip; + struct vmproc *vmp; + + /* Get chunks of available memory. */ + get_mem_chunks(mem_chunks); + + /* Initialize VM's process table. Request a copy of the system + * image table that is defined at the kernel level to see which + * slots to fill in. + */ + if (OK != (s=sys_getimage(image))) + vm_panic("couldn't get image table: %d\n", s); + + /* Set table to 0. This invalidates all slots (clear VMF_INUSE). */ + memset(vmproc, 0, sizeof(vmproc)); + + /* Walk through boot-time system processes that are alive + * now and make valid slot entries for them. + */ + for (ip = &image[0]; ip < &image[NR_BOOT_PROCS]; ip++) { + if(ip->proc_nr >= _NR_PROCS) { vm_panic("proc", ip->proc_nr); } + if(ip->proc_nr < 0 && ip->proc_nr != SYSTEM) continue; + + /* Initialize normal process table slot or special SYSTEM + * table slot. Kernel memory is already reserved. + */ + if(ip->proc_nr >= 0) { + vmp = &vmproc[ip->proc_nr]; + } else if(ip->proc_nr == SYSTEM) { + vmp = &vmproc[VMP_SYSTEM]; + } else { + vm_panic("init: crazy proc_nr", ip->proc_nr); + } + + /* reset fields as if exited */ + clear_proc(vmp); + + /* Get memory map for this process from the kernel. */ + if ((s=get_mem_map(ip->proc_nr, vmp->vm_arch.vm_seg)) != OK) + vm_panic("couldn't get process mem_map",s); + + /* Remove this memory from the free list. */ + reserve_proc_mem(mem_chunks, vmp->vm_arch.vm_seg); + + vmp->vm_flags = VMF_INUSE; + vmp->vm_endpoint = ip->endpoint; + vmp->vm_stacktop = + CLICK2ABS(vmp->vm_arch.vm_seg[S].mem_vir + + vmp->vm_arch.vm_seg[S].mem_len); + + if (vmp->vm_arch.vm_seg[T].mem_len != 0) + vmp->vm_flags |= VMF_SEPARATE; + } + + + /* Let architecture-dependent VM initialization use some memory. */ + arch_init_vm(mem_chunks); + + /* Architecture-dependent initialization. */ + pt_init(); + + /* Initialize tables to all physical memory. */ + mem_init(mem_chunks); + + /* Set up table of calls. */ +#define CALLMAP(code, func, thecaller) { int i; \ + if((i=CALLNUMBER(code)) < 0) { vm_panic(#code " invalid", (code)); } \ + if(vm_calls[i].vmc_func) { vm_panic("dup " #code , (code)); } \ + vm_calls[i].vmc_func = (func); \ + vm_calls[i].vmc_name = #code; \ + vm_calls[i].vmc_caller = (thecaller); \ +} + + /* Set call table to 0. This invalidates all calls (clear + * vmc_func). + */ + memset(vm_calls, 0, sizeof(vm_calls)); + + /* Requests from PM (restricted to be from PM only). */ + CALLMAP(VM_EXIT, do_exit, PM_PROC_NR); + CALLMAP(VM_FORK, do_fork, PM_PROC_NR); + CALLMAP(VM_BRK, do_brk, PM_PROC_NR); + CALLMAP(VM_EXEC_NEWMEM, do_exec_newmem, PM_PROC_NR); + CALLMAP(VM_PUSH_SIG, do_push_sig, PM_PROC_NR); + CALLMAP(VM_WILLEXIT, do_willexit, PM_PROC_NR); + CALLMAP(VM_ADDDMA, do_adddma, PM_PROC_NR); + CALLMAP(VM_DELDMA, do_deldma, PM_PROC_NR); + CALLMAP(VM_GETDMA, do_getdma, PM_PROC_NR); + CALLMAP(VM_ALLOCMEM, do_allocmem, PM_PROC_NR); + + /* Requests from tty device driver (/dev/video). */ + CALLMAP(VM_MAP_PHYS, do_map_phys, TTY_PROC_NR); + CALLMAP(VM_UNMAP_PHYS, do_unmap_phys, TTY_PROC_NR); + + /* Requests from userland (source unrestricted). */ + CALLMAP(VM_MMAP, do_mmap, ANY); + + /* Requests (actually replies) from VFS (restricted to VFS only). */ + CALLMAP(VM_VFS_REPLY_OPEN, do_vfs_reply, VFS_PROC_NR); + CALLMAP(VM_VFS_REPLY_MMAP, do_vfs_reply, VFS_PROC_NR); + CALLMAP(VM_VFS_REPLY_CLOSE, do_vfs_reply, VFS_PROC_NR); +} + diff --git a/servers/vm/mmap.c b/servers/vm/mmap.c new file mode 100644 index 000000000..2c07a0bce --- /dev/null +++ b/servers/vm/mmap.c @@ -0,0 +1,161 @@ + +#define _SYSTEM 1 + +#define VERBOSE 0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "glo.h" +#include "proto.h" +#include "util.h" +#include "region.h" + +/*===========================================================================* + * do_mmap * + *===========================================================================*/ +PUBLIC int do_mmap(message *m) +{ + int r, n; + struct vmproc *vmp; + int mfflags = 0; + struct vir_region *vr = NULL; + + if((r=vm_isokendpt(m->m_source, &n)) != OK) { + vm_panic("do_mmap: message from strange source", m->m_source); + } + + vmp = &vmproc[n]; + + if(m->VMM_FLAGS & MAP_LOWER16M) + printf("VM: warning for %d: MAP_LOWER16M not implemented\n", + m->m_source); + + if(!(vmp->vm_flags & VMF_HASPT)) + return ENXIO; + + if(m->VMM_FD == -1 || (m->VMM_FLAGS & MAP_ANON)) { + int s; + vir_bytes v; + size_t len = (vir_bytes) m->VMM_LEN; + + if(m->VMM_FD != -1) { + return EINVAL; + } + + if(m->VMM_FLAGS & MAP_CONTIG) mfflags |= MF_CONTIG; + if(m->VMM_FLAGS & MAP_PREALLOC) mfflags |= MF_PREALLOC; + + if(len % VM_PAGE_SIZE) + len += VM_PAGE_SIZE - (len % VM_PAGE_SIZE); + + if(!(vr = map_page_region(vmp, vmp->vm_stacktop, + VM_DATATOP, len, 0, + VR_ANON | VR_WRITABLE, mfflags))) { + return ENOMEM; + } + } else { + return ENOSYS; + } + + /* Return mapping, as seen from process. */ + vm_assert(vr); + m->VMM_RETADDR = arch_map2vir(vmp, vr->vaddr); + + return OK; +} + +/*===========================================================================* + * do_map_phys * + *===========================================================================*/ +PUBLIC int do_map_phys(message *m) +{ + int r, n; + struct vmproc *vmp; + endpoint_t target; + struct vir_region *vr; + + target = m->VMMP_EP; + if(target == SELF) + target = m->m_source; + + if((r=vm_isokendpt(target, &n)) != OK) { + printf("do_map_phys: bogus target %d\n", target); + return EINVAL; + } + + vmp = &vmproc[n]; + + if(!(vmp->vm_flags & VMF_HASPT)) + return ENXIO; + + if(!(vr = map_page_region(vmp, vmp->vm_stacktop, VM_DATATOP, + (vir_bytes) m->VMMP_LEN, (vir_bytes)m->VMMP_PHADDR, + VR_DIRECT | VR_NOPF | VR_WRITABLE, 0))) { + printf("VM:do_map_phys: map_page_region failed\n"); + return ENOMEM; + } + + m->VMMP_VADDR_REPLY = (void *) arch_map2vir(vmp, vr->vaddr); + + return OK; +} + +/*===========================================================================* + * do_unmap_phys * + *===========================================================================*/ +PUBLIC int do_unmap_phys(message *m) +{ + int r, n; + struct vmproc *vmp; + endpoint_t target; + struct vir_region *region; + + target = m->VMUP_EP; + if(target == SELF) + target = m->m_source; + + if((r=vm_isokendpt(target, &n)) != OK) { + printf("VM:do_unmap_phys: bogus target %d\n", target); + return EINVAL; + } + + vmp = &vmproc[n]; + + if(!(region = map_lookup(vmp, (vir_bytes) m->VMUM_ADDR))) { + printf("VM:do_unmap_phys: map_lookup failed\n"); + return EINVAL; + } + + if(!(region->flags & VR_DIRECT)) { + printf("VM:do_unmap_phys: region not a DIRECT mapping\n"); + return EINVAL; + } + + if(map_unmap_region(vmp, region) != OK) { + printf("VM:do_unmap_phys: map_unmap_region failed\n"); + return EINVAL; + } + + return OK; +} diff --git a/servers/vm/pagefaults.c b/servers/vm/pagefaults.c new file mode 100644 index 000000000..2f70d7c48 --- /dev/null +++ b/servers/vm/pagefaults.c @@ -0,0 +1,175 @@ + +#define _SYSTEM 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "glo.h" +#include "proto.h" +#include "memory.h" +#include "util.h" +#include "region.h" + +static char *pferr(int err) +{ + static char buf[100]; + + sprintf(buf, "err 0x%lx ", err); + if(PFERR_NOPAGE(err)) strcat(buf, "nopage "); + if(PFERR_PROT(err)) strcat(buf, "protection "); + if(PFERR_WRITE(err)) strcat(buf, "write"); + if(PFERR_READ(err)) strcat(buf, "read"); + + return buf; +} + +/*===========================================================================* + * handle_pagefaults * + *===========================================================================*/ +PUBLIC void handle_pagefaults(void) +{ + endpoint_t ep; + u32_t addr, err; + struct vmproc *vmp; + int r, s; + + while((r=arch_get_pagefault(&ep, &addr, &err)) == OK) { + struct vir_region *region; + vir_bytes offset; + int p, wr = PFERR_WRITE(err); + + if(vm_isokendpt(ep, &p) != OK) + vm_panic("handle_pagefaults: endpoint wrong", ep); + + vmp = &vmproc[p]; + vm_assert(vmp->vm_flags & VMF_INUSE); + + /* See if address is valid at all. */ + if(!(region = map_lookup(vmp, addr))) { + vm_assert(PFERR_NOPAGE(err)); + printf("VM: SIGSEGV %d bad addr 0x%lx error 0x%lx\n", + ep, addr, err); + if((s=sys_kill(vmp->vm_endpoint, SIGSEGV)) != OK) + vm_panic("sys_kill failed", s); + continue; + } + + /* Make sure this isn't a region that isn't supposed + * to cause pagefaults. + */ + vm_assert(!(region->flags & VR_NOPF)); + + /* If process was writing, see if it's writable. */ + if(!(region->flags & VR_WRITABLE) && wr) { + printf("VM: SIGSEGV %d ro map 0x%lx error 0x%lx\n", + ep, addr, err); + if((s=sys_kill(vmp->vm_endpoint, SIGSEGV)) != OK) + vm_panic("sys_kill failed", s); + continue; + } + + vm_assert(addr > region->vaddr); + offset = addr - region->vaddr; + + /* Access is allowed; handle it. */ + if((r=map_pagefault(vmp, region, offset, wr)) != OK) { + printf("VM: SIGSEGV %d pagefault not handled\n", ep); + if((s=sys_kill(vmp->vm_endpoint, SIGSEGV)) != OK) + vm_panic("sys_kill failed", s); + continue; + } + + + /* Pagefault is handled, so now reactivate the process. */ + if((s=sys_vmctl(ep, VMCTL_CLEAR_PAGEFAULT, r)) != OK) + vm_panic("handle_pagefaults: sys_vmctl failed", ep); + } + + return; +} + +/*===========================================================================* + * handle_memory * + *===========================================================================*/ +PUBLIC void handle_memory(void) +{ + int r, s; + endpoint_t who; + vir_bytes mem; + vir_bytes len; + int wrflag; + + while((r=sys_vmctl_get_memreq(&who, &mem, &len, &wrflag)) == OK) { + int p, r = OK; + struct vir_region *region; + struct vmproc *vmp; + vir_bytes o; + + if(vm_isokendpt(who, &p) != OK) + vm_panic("handle_memory: endpoint wrong", who); + vmp = &vmproc[p]; + + /* Page-align memory and length. */ + o = mem % VM_PAGE_SIZE; + mem -= o; + len += o; + o = len % VM_PAGE_SIZE; + if(o > 0) len += VM_PAGE_SIZE - o; + + if(!(region = map_lookup(vmp, mem))) { + printf("VM: handle_memory: memory doesn't exist\n"); + r = EFAULT; + } else if(mem + len > region->vaddr + region->length) { + vm_assert(region->vaddr <= mem); + vm_panic("handle_memory: not contained", NO_NUM); + } else if(!(region->flags & VR_WRITABLE) && wrflag) { + printf("VM: handle_memory: write to unwritable map\n"); + r = EFAULT; + } else { + vir_bytes offset; + vm_assert(region->vaddr <= mem); + vm_assert(!(region->flags & VR_NOPF)); + vm_assert(!(region->vaddr % VM_PAGE_SIZE)); + offset = mem - region->vaddr; + + r = map_handle_memory(vmp, region, offset, len, wrflag); + } + + if(r != OK) { + printf("VM: SIGSEGV %d, memory range not available\n", + vmp->vm_endpoint); + if((s=sys_kill(vmp->vm_endpoint, SIGSEGV)) != OK) + vm_panic("sys_kill failed", s); + } + + if(sys_vmctl(who, VMCTL_MEMREQ_REPLY, r) != OK) + vm_panic("handle_memory: sys_vmctl failed", r); + + if(r != OK) { + printf("VM: killing %d\n", vmp->vm_endpoint); + if((s=sys_kill(vmp->vm_endpoint, SIGSEGV)) != OK) + vm_panic("sys_kill failed", s); + } + } +} + diff --git a/servers/vm/proto.h b/servers/vm/proto.h new file mode 100644 index 000000000..9e0aa2b14 --- /dev/null +++ b/servers/vm/proto.h @@ -0,0 +1,139 @@ +/* Function prototypes. */ + +struct vmproc; +struct stat; +struct mem_map; +struct memory; + +#include +#include +#include +#include +#include +#include +#include "vmproc.h" +#include "vm.h" + +/* alloc.c */ +_PROTOTYPE( phys_clicks alloc_mem_f, (phys_clicks clicks, u32_t flags) ); +_PROTOTYPE( int do_adddma, (message *msg) ); +_PROTOTYPE( int do_deldma, (message *msg) ); +_PROTOTYPE( int do_getdma, (message *msg) ); +_PROTOTYPE( int do_allocmem, (message *msg) ); +_PROTOTYPE( void release_dma, (struct vmproc *vmp) ); + +_PROTOTYPE( void free_mem_f, (phys_clicks base, phys_clicks clicks) ); + +#define ALLOC_MEM(clicks, flags) alloc_mem_f(clicks, flags) +#define FREE_MEM(base, clicks) free_mem_f(base, clicks) + +_PROTOTYPE( void mem_init, (struct memory *chunks) ); +_PROTOTYPE( void memstats, (void) ); + +/* utility.c */ +_PROTOTYPE( int get_mem_map, (int proc_nr, struct mem_map *mem_map) ); +_PROTOTYPE( void get_mem_chunks, (struct memory *mem_chunks)); +_PROTOTYPE( void reserve_proc_mem, (struct memory *mem_chunks, + struct mem_map *map_ptr)); +_PROTOTYPE( int vm_isokendpt, (endpoint_t ep, int *proc) ); +_PROTOTYPE( int get_stack_ptr, (int proc_nr, vir_bytes *sp) ); + +/* exit.c */ +_PROTOTYPE( void clear_proc, (struct vmproc *vmp) ); +_PROTOTYPE( int do_exit, (message *msg) ); +_PROTOTYPE( int do_willexit, (message *msg) ); +_PROTOTYPE( void free_proc, (struct vmproc *vmp) ); + +/* fork.c */ +_PROTOTYPE( int do_fork, (message *msg) ); + +/* exec.c */ +_PROTOTYPE( struct vmproc *find_share, (struct vmproc *vmp_ign, Ino_t ino, + Dev_t dev, time_t ctime) ); +_PROTOTYPE( int do_exec_newmem, (message *msg) ); + +/* break.c */ +_PROTOTYPE( int do_brk, (message *msg) ); +_PROTOTYPE( int adjust, (struct vmproc *rmp, + vir_clicks data_clicks, vir_bytes sp) ); +_PROTOTYPE( int real_brk, (struct vmproc *vmp, vir_bytes v)); + +/* signal.c */ +_PROTOTYPE( int do_push_sig, (message *msg) ); + +/* vfs.c */ +_PROTOTYPE( int do_vfs_reply, (message *msg) ); +_PROTOTYPE( int vfs_open, (struct vmproc *for_who, callback_t callback, + cp_grant_id_t filename_gid, int filename_len, int flags, int mode)); +_PROTOTYPE( int vfs_close, (struct vmproc *for_who, callback_t callback, + int fd)); + +/* mmap.c */ +_PROTOTYPE(int do_mmap, (message *msg) ); +_PROTOTYPE(int do_map_phys, (message *msg) ); +_PROTOTYPE(int do_unmap_phys, (message *msg) ); + +/* pagefaults.c */ +_PROTOTYPE( void handle_pagefaults, (void) ); +_PROTOTYPE( void handle_memory, (void) ); + +/* $(ARCH)/pagetable.c */ +_PROTOTYPE( void pt_init, (void) ); +_PROTOTYPE( int pt_new, (pt_t *pt) ); +_PROTOTYPE( int pt_copy, (pt_t *src, pt_t *dst) ); +_PROTOTYPE( void pt_free, (pt_t *pt) ); +_PROTOTYPE( void pt_freerange, (pt_t *pt, vir_bytes lo, vir_bytes hi) ); +_PROTOTYPE( int pt_allocmap, (pt_t *pt, vir_bytes minv, vir_bytes maxv, + size_t bytes, u32_t pageflags, u32_t allocflags, vir_bytes *newv)); +_PROTOTYPE( int pt_writemap, (pt_t *pt, vir_bytes v, phys_bytes physaddr, + size_t bytes, u32_t flags, u32_t writemapflags)); +_PROTOTYPE( int pt_bind, (pt_t *pt, struct vmproc *who) ); +_PROTOTYPE( void *vm_allocpages, (phys_bytes *p, int pages, int cat)); +_PROTOTYPE( void pt_cycle, (void)); +_PROTOTYPE( int pt_mapkernel, (pt_t *pt)); +_PROTOTYPE( void phys_readaddr, (phys_bytes addr, phys_bytes *v1, phys_bytes *v2)); +_PROTOTYPE( void phys_writeaddr, (phys_bytes addr, phys_bytes v1, phys_bytes v2)); +#if SANITYCHECKS +_PROTOTYPE( void pt_sanitycheck, (pt_t *pt, char *file, int line) ); +#endif + +/* $(ARCH)/pagefaults.c */ +_PROTOTYPE( int arch_get_pagefault, (endpoint_t *who, vir_bytes *addr, u32_t *err)); + +/* slaballoc.c */ +_PROTOTYPE(void *slaballoc,(int bytes)); +_PROTOTYPE(void slabfree,(void *mem, int bytes)); +_PROTOTYPE(void slabstats,(void)); +#define SLABALLOC(var) (var = slaballoc(sizeof(*var))) +#define SLABFREE(ptr) slabfree(ptr, sizeof(*(ptr))) + +/* region.c */ +_PROTOTYPE(struct vir_region * map_page_region,(struct vmproc *vmp, \ + vir_bytes min, vir_bytes max, vir_bytes length, vir_bytes what, \ + u32_t flags, int mapflags)); +_PROTOTYPE(struct vir_region * map_proc_kernel,(struct vmproc *dst)); +_PROTOTYPE(int map_region_extend,(struct vir_region *vr, vir_bytes delta)); +_PROTOTYPE(int map_region_shrink,(struct vir_region *vr, vir_bytes delta)); +_PROTOTYPE(int map_unmap_region,(struct vmproc *vmp, struct vir_region *vr)); +_PROTOTYPE(int map_free_proc,(struct vmproc *vmp)); +_PROTOTYPE(int map_proc_copy,(struct vmproc *dst, struct vmproc *src)); +_PROTOTYPE(struct vir_region *map_lookup,(struct vmproc *vmp, vir_bytes addr)); +_PROTOTYPE(int map_pagefault,(struct vmproc *vmp, + struct vir_region *region, vir_bytes offset, int write)); +_PROTOTYPE(int map_handle_memory,(struct vmproc *vmp, + struct vir_region *region, vir_bytes offset, vir_bytes len, int write)); + +_PROTOTYPE(struct vir_region * map_region_lookup_tag, (struct vmproc *vmp, u32_t tag)); +_PROTOTYPE(void map_region_set_tag, (struct vir_region *vr, u32_t tag)); +_PROTOTYPE(u32_t map_region_get_tag, (struct vir_region *vr)); + + +#if SANITYCHECKS +_PROTOTYPE(void map_sanitycheck,(char *file, int line)); +#endif + +/* $(ARCH)/vm.c */ +_PROTOTYPE( void arch_init_vm, (struct memory mem_chunks[NR_MEMS])); +_PROTOTYPE( vir_bytes, arch_map2vir(struct vmproc *vmp, vir_bytes addr)); +_PROTOTYPE( vir_bytes, arch_vir2map(struct vmproc *vmp, vir_bytes addr)); + diff --git a/servers/vm/region.c b/servers/vm/region.c new file mode 100644 index 000000000..66f9778bc --- /dev/null +++ b/servers/vm/region.c @@ -0,0 +1,929 @@ + +#define _SYSTEM 1 + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "vm.h" +#include "proto.h" +#include "util.h" +#include "glo.h" +#include "region.h" +#include "sanitycheck.h" + +FORWARD _PROTOTYPE(int map_new_physblock, (struct vmproc *vmp, + struct vir_region *region, vir_bytes offset, vir_bytes length, + phys_bytes what, struct phys_region *physhint)); + +FORWARD _PROTOTYPE(int map_copy_ph_block, (struct vmproc *vmp, struct vir_region *region, struct phys_region *ph)); +FORWARD _PROTOTYPE(struct vir_region *map_copy_region, (struct vir_region *)); + +#if SANITYCHECKS + +FORWARD _PROTOTYPE(void map_printmap, (struct vmproc *vmp)); + +PRIVATE char *map_name(struct vir_region *vr) +{ + int type = vr->flags & (VR_ANON|VR_DIRECT); + switch(type) { + case VR_ANON: + return "anonymous"; + case VR_DIRECT: + return "direct"; + default: + vm_panic("unknown mapping type", type); + } + + return "NOTREACHED"; +} + + +/*===========================================================================* + * map_printmap * + *===========================================================================*/ +PRIVATE void map_printmap(vmp) +struct vmproc *vmp; +{ + struct vir_region *vr; + printf("%d:\n", vmp->vm_endpoint); + for(vr = vmp->vm_regions; vr; vr = vr->next) { + struct phys_region *ph; + printf("\t0x%08lx - 0x%08lx: %s (0x%lx)\n", + vr->vaddr, vr->vaddr + vr->length, map_name(vr), vr); + for(ph = vr->first; ph; ph = ph->next) { + printf("0x%lx-0x%lx(%d) ", + vr->vaddr + ph->ph->offset, + vr->vaddr + ph->ph->offset + ph->ph->length, + ph->ph->refcount); + } + printf("\n"); + } +} + +/*===========================================================================* + * map_sanitycheck * + *===========================================================================*/ +PUBLIC void map_sanitycheck(char *file, int line) +{ + struct vmproc *vmp; + +/* Macro for looping over all physical blocks of all regions of + * all processes. + */ +#define ALLREGIONS(regioncode, physcode) \ + for(vmp = vmproc; vmp <= &vmproc[_NR_PROCS]; vmp++) { \ + struct vir_region *vr; \ + if(!(vmp->vm_flags & VMF_INUSE)) \ + continue; \ + for(vr = vmp->vm_regions; vr; vr = vr->next) { \ + struct phys_region *pr; \ + regioncode; \ + for(pr = vr->first; pr; pr = pr->next) { \ + physcode; \ + } \ + } \ + } + + /* Do counting for consistency check. */ + ALLREGIONS(;,pr->ph->seencount = 0;); + ALLREGIONS(;,pr->ph->seencount++;); + + /* Do consistency check. */ + ALLREGIONS(if(vr->next) { + MYASSERT(vr->vaddr < vr->next->vaddr); + MYASSERT(vr->vaddr + vr->length <= vr->next->vaddr); + } + MYASSERT(!(vr->vaddr % VM_PAGE_SIZE));, + if(pr->ph->refcount != pr->ph->seencount) { + map_printmap(vmp); + printf("ph in vr 0x%lx: 0x%lx-0x%lx refcount %d " + "but seencount %lu\n", + vr, pr->ph->offset, + pr->ph->offset + pr->ph->length, + pr->ph->refcount, pr->ph->seencount); + } + MYASSERT(pr->ph->refcount == pr->ph->seencount); + MYASSERT(!(pr->ph->offset % VM_PAGE_SIZE)); + MYASSERT(!(pr->ph->length % VM_PAGE_SIZE));); +} +#endif + + +/*=========================================================================* + * map_ph_writept * + *=========================================================================*/ +PUBLIC int map_ph_writept(struct vmproc *vmp, struct vir_region *vr, + struct phys_block *pb, int *ropages, int *rwpages) +{ + int rw; + + vm_assert(!(vr->vaddr % VM_PAGE_SIZE)); + vm_assert(!(pb->length % VM_PAGE_SIZE)); + vm_assert(!(pb->offset % VM_PAGE_SIZE)); + vm_assert(pb->refcount > 0); + + if((vr->flags & VR_WRITABLE) + && (pb->refcount == 1 || (vr->flags & VR_DIRECT))) + rw = PTF_WRITE; + else + rw = 0; + +#if SANITYCHECKS + if(rwpages && ropages && (vr->flags & VR_ANON)) { + int pages; + pages = pb->length / VM_PAGE_SIZE; + if(rw) + (*rwpages) += pages; + else + (*ropages) += pages; + } +#endif + + if(pt_writemap(&vmp->vm_pt, vr->vaddr + pb->offset, + pb->phys, pb->length, PTF_PRESENT | PTF_USER | rw, + WMF_OVERWRITE) != OK) { + printf("VM: map_writept: pt_writemap failed\n"); + return ENOMEM; + } + + return OK; +} + +/*===========================================================================* + * map_region * + *===========================================================================*/ +PUBLIC struct vir_region *map_page_region(vmp, minv, maxv, length, + what, flags, mapflags) +struct vmproc *vmp; +vir_bytes minv; +vir_bytes maxv; +vir_bytes length; +vir_bytes what; +u32_t flags; +int mapflags; +{ + struct vir_region *vr, *prevregion = NULL, *newregion, + *firstregion = vmp->vm_regions; + vir_bytes startv; + int foundflag = 0; + + SANITYCHECK(SCL_FUNCTIONS); + + /* We must be in paged mode to be able to do this. */ + vm_assert(vm_paged); + + /* Length must be reasonable. */ + vm_assert(length > 0); + + /* Special case: allow caller to set maxv to 0 meaning 'I want + * it to be mapped in right here.' + */ + if(maxv == 0) { + maxv = minv + length; + + /* Sanity check. */ + if(maxv <= minv) { + printf("map_page_region: minv 0x%lx and bytes 0x%lx\n", + minv, length); + return NULL; + } + } + + /* Basic input sanity checks. */ + vm_assert(!(length % VM_PAGE_SIZE)); + if(minv >= maxv) { + printf("VM: 1 minv: 0x%lx maxv: 0x%lx length: 0x%lx\n", + minv, maxv, length); + } + vm_assert(minv < maxv); + vm_assert(minv + length <= maxv); + +#define FREEVRANGE(rangestart, rangeend, foundcode) { \ + vir_bytes frstart = (rangestart), frend = (rangeend); \ + frstart = MAX(frstart, minv); \ + frend = MIN(frend, maxv); \ + if(frend > frstart && (frend - frstart) >= length) { \ + startv = frstart; \ + foundflag = 1; \ + foundcode; \ + } } + + /* This is the free virtual address space before the first region. */ + FREEVRANGE(0, firstregion ? firstregion->vaddr : VM_DATATOP, ;); + + if(!foundflag) { + for(vr = vmp->vm_regions; vr && !foundflag; vr = vr->next) { + FREEVRANGE(vr->vaddr + vr->length, + vr->next ? vr->next->vaddr : VM_DATATOP, + prevregion = vr;); + } + } + + if(!foundflag) { + printf("VM: map_page_region: no 0x%lx bytes found for %d between 0x%lx and 0x%lx\n", + length, vmp->vm_endpoint, minv, maxv); + return NULL; + } + +#if SANITYCHECKS + if(prevregion) vm_assert(prevregion->vaddr < startv); +#endif + + /* However we got it, startv must be in the requested range. */ + vm_assert(startv >= minv); + vm_assert(startv < maxv); + vm_assert(startv + length <= maxv); + + /* Now we want a new region. */ + if(!SLABALLOC(newregion)) { + printf("VM: map_page_region: allocating region failed\n"); + return NULL; + } + + /* Fill in node details. */ + newregion->vaddr = startv; + newregion->length = length; + newregion->first = NULL; + newregion->flags = flags; + newregion->tag = VRT_NONE; + + /* If this is a 'direct' mapping, try to actually map it. */ + if(flags & VR_DIRECT) { + vm_assert(!(length % VM_PAGE_SIZE)); + vm_assert(!(startv % VM_PAGE_SIZE)); + vm_assert(!newregion->first); + vm_assert(!(mapflags & MF_PREALLOC)); + if(map_new_physblock(vmp, newregion, 0, length, what, NULL) != OK) { + printf("VM: map_new_physblock failed\n"); + SLABFREE(newregion); + return NULL; + } + vm_assert(newregion->first); + vm_assert(!newregion->first->next); + if(map_ph_writept(vmp, newregion, newregion->first->ph, NULL, NULL) != OK) { + printf("VM: map_region_writept failed\n"); + SLABFREE(newregion); + return NULL; + } + } + + if((flags & VR_ANON) && (mapflags & MF_PREALLOC)) { + if(map_handle_memory(vmp, newregion, 0, length, 1) != OK) { + printf("VM:map_page_region: prealloc failed\n"); + SLABFREE(newregion); + return NULL; + } + } + + /* Link it. */ + if(prevregion) { + vm_assert(prevregion->vaddr < newregion->vaddr); + newregion->next = prevregion->next; + prevregion->next = newregion; + } else { + newregion->next = vmp->vm_regions; + vmp->vm_regions = newregion; + } + +#if SANITYCHECKS + vm_assert(startv == newregion->vaddr); + if(newregion->next) { + vm_assert(newregion->vaddr < newregion->next->vaddr); + } +#endif + + SANITYCHECK(SCL_FUNCTIONS); + + return newregion; +} + + +/*===========================================================================* + * map_free * + *===========================================================================*/ +PRIVATE int map_free(struct vir_region *region) +{ + struct phys_region *pr, *nextpr; + + for(pr = region->first; pr; pr = nextpr) { + vm_assert(pr->ph->refcount > 0); + pr->ph->refcount--; + nextpr = pr->next; + region->first = nextpr; /* For sanity checks. */ + if(pr->ph->refcount == 0) { + if(region->flags & VR_ANON) { + FREE_MEM(ABS2CLICK(pr->ph->phys), + ABS2CLICK(pr->ph->length)); + } else if(region->flags & VR_DIRECT) { + ; /* No action required. */ + } else { + vm_panic("strange phys flags", NO_NUM); + } + SLABFREE(pr->ph); + } + SLABFREE(pr); + } + + SLABFREE(region); + + return OK; +} + +/*========================================================================* + * map_free_proc * + *========================================================================*/ +PUBLIC int map_free_proc(vmp) +struct vmproc *vmp; +{ + struct vir_region *r, *nextr; + + SANITYCHECK(SCL_FUNCTIONS); + + for(r = vmp->vm_regions; r; r = nextr) { + nextr = r->next; + map_free(r); + vmp->vm_regions = nextr; /* For sanity checks. */ + } + + vmp->vm_regions = NULL; + + SANITYCHECK(SCL_FUNCTIONS); + + return OK; +} + +/*===========================================================================* + * map_lookup * + *===========================================================================*/ +PUBLIC struct vir_region *map_lookup(vmp, offset) +struct vmproc *vmp; +vir_bytes offset; +{ + struct vir_region *r; + + SANITYCHECK(SCL_FUNCTIONS); + + if(!vmp->vm_regions) + vm_panic("process has no regions", vmp->vm_endpoint); + + for(r = vmp->vm_regions; r; r = r->next) { + if(offset >= r->vaddr && offset < r->vaddr + r->length) + return r; + } + + SANITYCHECK(SCL_FUNCTIONS); + + return NULL; +} + + +/*===========================================================================* + * map_new_physblock * + *===========================================================================*/ +PRIVATE int map_new_physblock(vmp, region, offset, length, what_mem, physhint) +struct vmproc *vmp; +struct vir_region *region; +vir_bytes offset; +vir_bytes length; +phys_bytes what_mem; +struct phys_region *physhint; +{ + struct phys_region *physr, *newphysr; + struct phys_block *newpb; + phys_bytes mem_clicks, clicks; + vir_bytes mem; + + SANITYCHECK(SCL_FUNCTIONS); + + vm_assert(!(length % VM_PAGE_SIZE)); + if(!physhint) physhint = region->first; + + /* Allocate things necessary for this chunk of memory. */ + if(!SLABALLOC(newphysr)) + return ENOMEM; + if(!SLABALLOC(newpb)) { + SLABFREE(newphysr); + return ENOMEM; + } + + /* Memory for new physical block. */ + clicks = CLICKSPERPAGE * length / VM_PAGE_SIZE; + if(!what_mem) { + if((mem_clicks = ALLOC_MEM(clicks, PAF_CLEAR)) == NO_MEM) { + SLABFREE(newpb); + SLABFREE(newphysr); + return ENOMEM; + } + mem = CLICK2ABS(mem_clicks); + } else { + mem = what_mem; + } + + /* New physical block. */ + newpb->phys = mem; + newpb->refcount = 1; + newpb->offset = offset; + newpb->length = length; + + /* New physical region. */ + newphysr->ph = newpb; + + /* Update pagetable. */ + vm_assert(!(length % VM_PAGE_SIZE)); + vm_assert(!(newpb->length % VM_PAGE_SIZE)); + if(map_ph_writept(vmp, region, newpb, NULL, NULL) != OK) { + if(!what_mem) + FREE_MEM(mem_clicks, clicks); + SLABFREE(newpb); + SLABFREE(newphysr); + return ENOMEM; + } + + if(!region->first || offset < region->first->ph->offset) { + /* Special case: offset is before start. */ + if(region->first) { + vm_assert(offset + length <= region->first->ph->offset); + } + newphysr->next = region->first; + region->first = newphysr; + } else { + for(physr = physhint; physr; physr = physr->next) { + if(!physr->next || physr->next->ph->offset > offset) { + newphysr->next = physr->next; + physr->next = newphysr; + break; + } + } + + /* Loop must have put the node somewhere. */ + vm_assert(physr->next == newphysr); + } + + SANITYCHECK(SCL_FUNCTIONS); + + return OK; +} + + +/*===========================================================================* + * map_copy_ph_block * + *===========================================================================*/ +PRIVATE int map_copy_ph_block(vmp, region, ph) +struct vmproc *vmp; +struct vir_region *region; +struct phys_region *ph; +{ + int r; + phys_bytes newmem, newmem_cl, clicks; + struct phys_block *newpb; + + SANITYCHECK(SCL_FUNCTIONS); + + /* This is only to be done if there is more than one copy. */ + vm_assert(ph->ph->refcount > 1); + + /* Do actal copy on write; allocate new physblock. */ + if(!SLABALLOC(newpb)) { + printf("VM: map_copy_ph_block: couldn't allocate newpb\n"); + SANITYCHECK(SCL_FUNCTIONS); + return ENOMEM; + } + + clicks = CLICKSPERPAGE * ph->ph->length / VM_PAGE_SIZE; + vm_assert(CLICK2ABS(clicks) == ph->ph->length); + if((newmem_cl = ALLOC_MEM(clicks, 0)) == NO_MEM) { + SLABFREE(newpb); + return ENOMEM; + } + newmem = CLICK2ABS(newmem_cl); + + ph->ph->refcount--; + vm_assert(ph->ph->refcount > 0); + newpb->length = ph->ph->length; + newpb->offset = ph->ph->offset; + newpb->refcount = 1; + newpb->phys = newmem; + + /* Copy old memory to new memory. */ + if((r=sys_abscopy(ph->ph->phys, newpb->phys, newpb->length)) != OK) { + printf("VM: map_copy_ph_block: sys_abscopy failed\n"); + SANITYCHECK(SCL_FUNCTIONS); + return r; + } + +#if VMSTATS + vmp->vm_bytecopies += newpb->length; +#endif + + /* Reference new block. */ + ph->ph = newpb; + + /* Check reference counts. */ + SANITYCHECK(SCL_DETAIL); + + /* Update pagetable with new address. + * This will also make it writable. + */ + r = map_ph_writept(vmp, region, ph->ph, NULL, NULL); + if(r != OK) + vm_panic("map_copy_ph_block: map_ph_writept failed", r); + + SANITYCHECK(SCL_FUNCTIONS); + + return OK; +} + +/*===========================================================================* + * map_pagefault * + *===========================================================================*/ +PUBLIC int map_pagefault(vmp, region, offset, write) +struct vmproc *vmp; +struct vir_region *region; +vir_bytes offset; +int write; +{ + vir_bytes virpage; + struct phys_region *ph; + int r; + + vm_assert(offset >= 0); + vm_assert(offset < region->length); + + vm_assert(region->flags & VR_ANON); + vm_assert(!(region->vaddr % VM_PAGE_SIZE)); + + virpage = offset - offset % VM_PAGE_SIZE; + + SANITYCHECK(SCL_FUNCTIONS); + + for(ph = region->first; ph; ph = ph->next) + if(ph->ph->offset <= offset && offset < ph->ph->offset + ph->ph->length) + break; + + if(ph) { + /* Pagefault in existing block. Do copy-on-write. */ + vm_assert(write); + vm_assert(region->flags & VR_WRITABLE); + vm_assert(ph->ph->refcount > 0); + + if(ph->ph->refcount == 1) + r = map_ph_writept(vmp, region, ph->ph, NULL, NULL); + else + r = map_copy_ph_block(vmp, region, ph); + } else { + /* Pagefault in non-existing block. Map in new block. */ +#if 0 + if(!write) { + printf("VM: read from uninitialized memory by %d\n", + vmp->vm_endpoint); + } +#endif + r = map_new_physblock(vmp, region, virpage, VM_PAGE_SIZE, 0, + region->first); + } + + if(r != OK) + printf("VM: map_pagefault: failed (%d)\n", r); + + SANITYCHECK(SCL_FUNCTIONS); + + return r; +} + +/*===========================================================================* + * map_handle_memory * + *===========================================================================*/ +PUBLIC int map_handle_memory(vmp, region, offset, length, write) +struct vmproc *vmp; +struct vir_region *region; +vir_bytes offset, length; +int write; +{ + struct phys_region *physr; + int changes = 0; + +#define FREE_RANGE_HERE(er1, er2) { \ + struct phys_region *r1 = (er1), *r2 = (er2); \ + vir_bytes start = offset, end = offset + length; \ + if(r1) { start = MAX(start, r1->ph->offset + r1->ph->length); } \ + if(r2) { end = MIN(end, r2->ph->offset); } \ + if(start < end) { \ + int r; \ + SANITYCHECK(SCL_DETAIL); \ + if((r=map_new_physblock(vmp, region, start, \ + end-start, 0, r1 ? r1 : r2)) != OK) { \ + SANITYCHECK(SCL_DETAIL); \ + return r; \ + } \ + changes++; \ + } } + + SANITYCHECK(SCL_FUNCTIONS); + + vm_assert(region->flags & VR_ANON); + vm_assert(!(region->vaddr % VM_PAGE_SIZE)); + vm_assert(!(offset % VM_PAGE_SIZE)); + vm_assert(!(length % VM_PAGE_SIZE)); + vm_assert(!write || (region->flags & VR_WRITABLE)); + + FREE_RANGE_HERE(NULL, region->first); + + for(physr = region->first; physr; physr = physr->next) { + int r; + + SANITYCHECK(SCL_DETAIL); + + if(write) { + vm_assert(physr->ph->refcount > 0); + if(physr->ph->refcount > 1) { + SANITYCHECK(SCL_DETAIL); + r = map_copy_ph_block(vmp, region, physr); + if(r != OK) { + printf("VM: map_handle_memory: no copy\n"); + return r; + } + changes++; + SANITYCHECK(SCL_DETAIL); + } else { + SANITYCHECK(SCL_DETAIL); + if((r=map_ph_writept(vmp, region, physr->ph, NULL, NULL)) != OK) { + printf("VM: map_ph_writept failed\n"); + return r; + } + changes++; + SANITYCHECK(SCL_DETAIL); + } + } + + SANITYCHECK(SCL_DETAIL); + FREE_RANGE_HERE(physr, physr->next); + SANITYCHECK(SCL_DETAIL); + } + + SANITYCHECK(SCL_FUNCTIONS); + +#if SANITYCHECKS + if(changes == 0) { + vm_panic("no changes?!", changes); + } +#endif + + return OK; +} + +#if SANITYCHECKS +static int countregions(struct vir_region *vr) +{ + int n = 0; + struct phys_region *ph; + for(ph = vr->first; ph; ph = ph->next) + n++; + return n; +} +#endif + +/*===========================================================================* + * map_copy_region * + *===========================================================================*/ +PRIVATE struct vir_region *map_copy_region(struct vir_region *vr) +{ + struct vir_region *newvr; + struct phys_region *ph, *prevph = NULL; +#if SANITYCHECKS + int cr; + cr = countregions(vr); +#endif + if(!SLABALLOC(newvr)) + return NULL; + *newvr = *vr; + newvr->first = NULL; + newvr->next = NULL; + + SANITYCHECK(SCL_FUNCTIONS); + + for(ph = vr->first; ph; ph = ph->next) { + struct phys_region *newph; + if(!SLABALLOC(newph)) { + map_free(newvr); + return NULL; + } + newph->next = NULL; + newph->ph = ph->ph; + if(prevph) prevph->next = newph; + else newvr->first = newph; + prevph = newph; + SANITYCHECK(SCL_DETAIL); + vm_assert(countregions(vr) == cr); + } + + vm_assert(countregions(vr) == countregions(newvr)); + + SANITYCHECK(SCL_FUNCTIONS); + + return newvr; +} + +/*=========================================================================* + * map_writept * + *=========================================================================*/ +PUBLIC int map_writept(struct vmproc *vmp) +{ + struct vir_region *vr; + struct phys_region *ph; + int ropages = 0, rwpages = 0; + + for(vr = vmp->vm_regions; vr; vr = vr->next) + for(ph = vr->first; ph; ph = ph->next) { + map_ph_writept(vmp, vr, ph->ph, &ropages, &rwpages); + } + + return OK; +} + +/*========================================================================* + * map_proc_copy * + *========================================================================*/ +PUBLIC int map_proc_copy(dst, src) +struct vmproc *dst; +struct vmproc *src; +{ + struct vir_region *vr, *prevvr = NULL; + dst->vm_regions = NULL; + + SANITYCHECK(SCL_FUNCTIONS); + for(vr = src->vm_regions; vr; vr = vr->next) { + struct vir_region *newvr; + struct phys_region *ph; + SANITYCHECK(SCL_DETAIL); + if(!(newvr = map_copy_region(vr))) { + map_free_proc(dst); + SANITYCHECK(SCL_FUNCTIONS); + return ENOMEM; + } + SANITYCHECK(SCL_DETAIL); + if(prevvr) { prevvr->next = newvr; } + else { dst->vm_regions = newvr; } + for(ph = vr->first; ph; ph = ph->next) { + vm_assert(ph->ph->refcount > 0); + ph->ph->refcount++; + vm_assert(ph->ph->refcount > 1); + } + SANITYCHECK(SCL_DETAIL); + prevvr = newvr; + SANITYCHECK(SCL_DETAIL); + } + SANITYCHECK(SCL_DETAIL); + + map_writept(src); + map_writept(dst); + + SANITYCHECK(SCL_FUNCTIONS); + return OK; +} + +/*========================================================================* + * map_proc_kernel * + *========================================================================*/ +PUBLIC struct vir_region *map_proc_kernel(struct vmproc *vmp) +{ + struct vir_region *vr; + + /* We assume these are the first regions to be mapped to + * make the function a bit simpler (free all regions on error). + */ + vm_assert(!vmp->vm_regions); + vm_assert(vmproc[VMP_SYSTEM].vm_flags & VMF_INUSE); + vm_assert(!(KERNEL_TEXT % VM_PAGE_SIZE)); + vm_assert(!(KERNEL_TEXT_LEN % VM_PAGE_SIZE)); + vm_assert(!(KERNEL_DATA % VM_PAGE_SIZE)); + vm_assert(!(KERNEL_DATA_LEN % VM_PAGE_SIZE)); + + if(!(vr = map_page_region(vmp, KERNEL_TEXT, 0, KERNEL_TEXT_LEN, + KERNEL_TEXT, VR_DIRECT | VR_WRITABLE | VR_NOPF, 0)) || + !(vr = map_page_region(vmp, KERNEL_DATA, 0, KERNEL_DATA_LEN, + KERNEL_DATA, VR_DIRECT | VR_WRITABLE | VR_NOPF, 0))) { + map_free_proc(vmp); + return NULL; + } + + return vr; /* Return pointer not useful, just non-NULL. */ +} + +/*========================================================================* + * map_region_extend * + *========================================================================*/ +PUBLIC int map_region_extend(struct vir_region *vr, vir_bytes delta) +{ + vir_bytes end; + + vm_assert(vr); + vm_assert(vr->flags & VR_ANON); + vm_assert(!(delta % VM_PAGE_SIZE)); + + if(!delta) return OK; + end = vr->vaddr + vr->length; + vm_assert(end >= vr->vaddr); + + if(end + delta <= end) { + printf("VM: strange delta 0x%lx\n", delta); + return ENOMEM; + } + + if(!vr->next || end + delta <= vr->next->vaddr) { + vr->length += delta; + return OK; + } + + return ENOMEM; +} + +/*========================================================================* + * map_region_shrink * + *========================================================================*/ +PUBLIC int map_region_shrink(struct vir_region *vr, vir_bytes delta) +{ + vm_assert(vr); + vm_assert(vr->flags & VR_ANON); + vm_assert(!(delta % VM_PAGE_SIZE)); + + printf("VM: ignoring region shrink\n"); + + return OK; +} + +PUBLIC struct vir_region *map_region_lookup_tag(vmp, tag) +struct vmproc *vmp; +u32_t tag; +{ + struct vir_region *vr; + + for(vr = vmp->vm_regions; vr; vr = vr->next) + if(vr->tag == tag) + return vr; + + return NULL; +} + +PUBLIC void map_region_set_tag(struct vir_region *vr, u32_t tag) +{ + vr->tag = tag; +} + +PUBLIC u32_t map_region_get_tag(struct vir_region *vr) +{ + return vr->tag; +} + +/*========================================================================* + * map_unmap_region * + *========================================================================*/ +PUBLIC int map_unmap_region(struct vmproc *vmp, struct vir_region *region) +{ + struct vir_region *r, *nextr, *prev = NULL; + + SANITYCHECK(SCL_FUNCTIONS); + + for(r = vmp->vm_regions; r; r = r->next) { + if(r == region) + break; + + prev = r; + } + + SANITYCHECK(SCL_DETAIL); + + if(r == NULL) + vm_panic("map_unmap_region: region not found\n", NO_NUM); + + if(!prev) + vmp->vm_regions = r->next; + else + prev->next = r->next; + map_free(r); + + SANITYCHECK(SCL_DETAIL); + + if(pt_writemap(&vmp->vm_pt, r->vaddr, + 0, r->length, 0, WMF_OVERWRITE) != OK) { + printf("VM: map_unmap_region: pt_writemap failed\n"); + return ENOMEM; + } + + SANITYCHECK(SCL_FUNCTIONS); + + return OK; +} diff --git a/servers/vm/region.h b/servers/vm/region.h new file mode 100644 index 000000000..a134ef73c --- /dev/null +++ b/servers/vm/region.h @@ -0,0 +1,46 @@ + +#ifndef _REGION_H +#define _REGION_H 1 + +struct phys_block { +#if SANITYCHECKS + u32_t seencount; +#endif + vir_bytes offset; /* offset from start of vir region */ + vir_bytes length; /* no. of contiguous bytes */ + phys_bytes phys; /* physical memory */ + u8_t refcount; /* Refcount of these pages */ +}; + +struct phys_region { + struct phys_region *next; /* next contiguous block */ + struct phys_block *ph; +}; + +struct vir_region { + struct vir_region *next; /* next virtual region in this process */ + vir_bytes vaddr; /* virtual address, offset from pagetable */ + vir_bytes length; /* length in bytes */ + struct phys_region *first; /* phys regions in vir region */ + u16_t flags; + u32_t tag; /* Opaque to mapping code. */ +}; + +/* Mapping flags: */ +#define VR_WRITABLE 0x01 /* Process may write here. */ +#define VR_NOPF 0x02 /* May not generate page faults. */ + +/* Mapping type: */ +#define VR_ANON 0x10 /* Memory to be cleared and allocated */ +#define VR_DIRECT 0x20 /* Mapped, but not managed by VM */ + +/* Tag values: */ +#define VRT_NONE 0xBEEF0000 +#define VRT_HEAP 0xBEEF0001 + +/* map_page_region flags */ +#define MF_PREALLOC 0x01 +#define MF_CONTIG 0x02 + +#endif + diff --git a/servers/vm/sanitycheck.h b/servers/vm/sanitycheck.h new file mode 100644 index 000000000..cc53879c9 --- /dev/null +++ b/servers/vm/sanitycheck.h @@ -0,0 +1,46 @@ +#ifndef _SANITYCHECK_H +#define _SANITYCHECK_H 1 + +#include "vm.h" +#include "glo.h" + +#if SANITYCHECKS + +/* This macro is used in the sanity check functions, where file and + * line are function arguments. + */ +#define MYASSERT(c) do { if(!(c)) { \ + printf("VM:%s:%d: %s failed\n", file, line, #c); \ + vm_panic("sanity check failed", NO_NUM); } } while(0) + +#define SANITYCHECK(l) if((l) <= vm_sanitychecklevel) { \ + int failflag = 0; \ + u32_t *origptr = CHECKADDR;\ + int _sanep; \ + struct vmproc *vmp; \ + \ + for(_sanep = 0; _sanep < sizeof(data1) / sizeof(*origptr); \ + _sanep++) { \ + if(origptr[_sanep] != data1[_sanep]) { \ + printf("%d: %08lx != %08lx ", \ + _sanep, origptr[_sanep], data1[_sanep]); failflag = 1; \ + } \ + } \ + if(failflag) { \ + printf("%s:%d: memory corruption test failed\n", \ + __FILE__, __LINE__); \ + vm_panic("memory corruption", NO_NUM); \ + } \ + for(vmp = vmproc; vmp <= &vmproc[_NR_PROCS]; vmp++) { \ + if((vmp->vm_flags & (VMF_INUSE | VMF_HASPT)) == \ + (VMF_INUSE | VMF_HASPT)) { \ + pt_sanitycheck(&vmp->vm_pt, __FILE__, __LINE__); \ + } \ + } \ + map_sanitycheck(__FILE__, __LINE__); \ + } +#else +#define SANITYCHECK +#endif + +#endif diff --git a/servers/vm/signal.c b/servers/vm/signal.c new file mode 100644 index 000000000..a43e76962 --- /dev/null +++ b/servers/vm/signal.c @@ -0,0 +1,64 @@ + +#define _SYSTEM 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "glo.h" +#include "vm.h" +#include "proto.h" +#include "util.h" + +#define DATA_CHANGED 1 /* flag value when data segment size changed */ +#define STACK_CHANGED 2 /* flag value when stack size changed */ + +/*===========================================================================* + * do_push_sig * + *===========================================================================*/ +PUBLIC int do_push_sig(message *msg) +{ + int r, n; + endpoint_t ep; + vir_bytes sp; + struct vmproc *vmp; + + ep = msg->VMPS_ENDPOINT; + + if((r=vm_isokendpt(ep, &n)) != OK) { + printf("VM: bogus endpoint %d from %d\n", ep, msg->m_source); + return r; + } + vmp = &vmproc[n]; + + if ((r=get_stack_ptr(ep, &sp)) != OK) + vm_panic("couldn't get new stack pointer (for sig)",r); + + /* Save old SP for caller */ + msg->VMPS_OLD_SP = (char *) sp; + + /* Make room for the sigcontext and sigframe struct. */ + sp -= sizeof(struct sigcontext) + + 3 * sizeof(char *) + 2 * sizeof(int); + + if ((r=adjust(vmp, vmp->vm_arch.vm_seg[D].mem_len, sp)) != OK) { + printf("VM: do_push_sig: adjust() failed: %d\n", r); + return r; + } + + return OK; +} + diff --git a/servers/vm/slaballoc.c b/servers/vm/slaballoc.c new file mode 100644 index 000000000..87b366138 --- /dev/null +++ b/servers/vm/slaballoc.c @@ -0,0 +1,399 @@ + +#define _SYSTEM 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "glo.h" +#include "proto.h" +#include "util.h" +#include "sanitycheck.h" + +#define SLABSIZES 60 + +#define ITEMSPERPAGE(s, bytes) (DATABYTES / (bytes)) + +#define ELBITS (sizeof(element_t)*8) +#define BITPAT(b) (1UL << ((b) % ELBITS)) +#define BITEL(f, b) (f)->sdh.usebits[(b)/ELBITS] + + +#define OFF(f, b) vm_assert(!GETBIT(f, b)) +#define ON(f, b) vm_assert(GETBIT(f, b)) + +#define GETBIT(f, b) (BITEL(f,b) & BITPAT(b)) +#define SETBIT(f, b) {OFF(f,b); (BITEL(f,b)|= BITPAT(b)); (f)->sdh.nused++; } +#define CLEARBIT(f, b) {ON(f, b); (BITEL(f,b)&=~BITPAT(b)); (f)->sdh.nused--; (f)->sdh.freeguess = (b); } + +#define MINSIZE 8 +#define MAXSIZE (SLABSIZES-1+MINSIZE) +#define USEELEMENTS (1+(VM_PAGE_SIZE/MINSIZE/8)) + +PRIVATE int pages = 0; + +typedef u8_t element_t; +#define BITS_FULL (~(element_t)0) +typedef element_t elements_t[USEELEMENTS]; + +/* This file is too low-level to have global SANITYCHECKs everywhere, + * as the (other) data structures are often necessarily in an + * inconsistent state during a slaballoc() / slabfree(). So only do + * our own sanity checks here, with SLABSANITYCHECK. + */ +#if SANITYCHECKS +#define SLABSANITYCHECK(l) if((l) <= vm_sanitychecklevel) { \ + slab_sanitycheck(__FILE__, __LINE__); } +#else +#define SLABSANITYCHECK(l) +#endif + +struct sdh { + u8_t list; + u16_t nused; /* Number of data items used in this slab. */ +#if SANITYCHECKS + u32_t magic; +#endif + int freeguess; + struct slabdata *next, *prev; + elements_t usebits; + phys_bytes phys; +}; + +#define DATABYTES (VM_PAGE_SIZE-sizeof(struct sdh)) + +#define MAGIC 0x1f5b842f +#define JUNK 0xdeadbeef +#define NOJUNK 0xc0ffee + +#define LIST_UNUSED 0 +#define LIST_FREE 1 +#define LIST_USED 2 +#define LIST_FULL 3 +#define LIST_NUMBER 4 + +PRIVATE struct slabheader { + struct slabdata { + struct sdh sdh; + u8_t data[DATABYTES]; + } *list_head[LIST_NUMBER]; +} slabs[SLABSIZES]; + +#define GETSLAB(b, s) { \ + int i; \ + vm_assert((b) >= MINSIZE); \ + i = (b) - MINSIZE; \ + vm_assert((i) < SLABSIZES); \ + vm_assert((i) >= 0); \ + s = &slabs[i]; \ +} + +#define LH(sl, l) (sl)->list_head[l] + +#define MOVEHEAD(sl, l1, l2) { \ + struct slabdata *t; \ + vm_assert(LH(sl,l1)); \ + REMOVEHEAD(sl, l1, t); \ + ADDHEAD(t, sl, l2); \ +} + +#define REMOVEHEAD(sl, list, to) { \ + (to) = LH(sl, list); \ + vm_assert(to); \ + LH(sl, list) = (to)->sdh.next; \ + if(LH(sl, list)) LH(sl, list) = NULL; \ + vm_assert((to)->sdh.magic == MAGIC);\ + vm_assert(!(to)->sdh.prev); \ +} + +#define ADDHEAD(nw, sl, l) { \ + vm_assert((nw)->sdh.magic == MAGIC); \ + (nw)->sdh.next = LH(sl, l); \ + (nw)->sdh.prev = NULL; \ + (nw)->sdh.list = l; \ + LH(sl, l) = (nw); \ + if((nw)->sdh.next) (nw)->sdh.next->sdh.prev = (nw); \ +} + +#define UNLINKNODE(n) { \ + if((f)->sdh.prev) (f)->sdh.prev->sdh.next = (f)->sdh.next; \ + if((f)->sdh.next) (f)->sdh.next->sdh.prev = (f)->sdh.prev; \ + } + +struct slabdata *newslabdata(int list) +{ + struct slabdata *n; + phys_bytes p; + + vm_assert(sizeof(*n) == VM_PAGE_SIZE); + + if(!(n = vm_allocpages(&p, 1, VMP_SLAB))) + return NULL; + memset(n->sdh.usebits, 0, sizeof(n->sdh.usebits)); + pages++; + + n->sdh.phys = p; +#if SANITYCHECKS + n->sdh.magic = MAGIC; +#endif + n->sdh.nused = 0; + n->sdh.freeguess = 0; + n->sdh.list = list; + + return n; +} + +#if SANITYCHECKS + +/*===========================================================================* + * checklist * + *===========================================================================*/ +PRIVATE int checklist(char *file, int line, + struct slabheader *s, int l, int bytes) +{ + struct slabdata *n = s->list_head[l]; + int ch = 0; + + while(n) { + int count = 0, i; + MYASSERT(n->sdh.list == l); + MYASSERT(n->sdh.magic == MAGIC); + if(n->sdh.prev) + MYASSERT(n->sdh.prev->sdh.next == n); + else + MYASSERT(s->list_head[l] == n); + if(n->sdh.next) MYASSERT(n->sdh.next->sdh.prev == n); + for(i = 0; i < USEELEMENTS*8; i++) + if(i >= ITEMSPERPAGE(s, bytes)) + MYASSERT(!GETBIT(n, i)); + else + if(GETBIT(n,i)) + count++; + MYASSERT(count == n->sdh.nused); + ch += count; + n = n->sdh.next; + } + + return ch; +} + +/*===========================================================================* + * void slab_sanitycheck * + *===========================================================================*/ +PUBLIC void slab_sanitycheck(char *file, int line) +{ + int s; + for(s = 0; s < SLABSIZES; s++) { + int l; + for(l = 0; l < LIST_NUMBER; l++) { + checklist(file, line, &slabs[s], l, s + MINSIZE); + } + } +} + +#endif + +/*===========================================================================* + * void *slaballoc * + *===========================================================================*/ +PUBLIC void *slaballoc(int bytes) +{ + int i, n = 0; + struct slabheader *s; + struct slabdata *firstused; + + SLABSANITYCHECK(SCL_FUNCTIONS); + + /* Retrieve entry in slabs[]. */ + GETSLAB(bytes, s); + vm_assert(s); + + /* To make the common case more common, make space in the 'used' + * queue first. + */ + if(!LH(s, LIST_USED)) { + /* Make sure there is something on the freelist. */ + SLABSANITYCHECK(SCL_DETAIL); + if(!LH(s, LIST_FREE)) { + struct slabdata *n = newslabdata(LIST_FREE); + SLABSANITYCHECK(SCL_DETAIL); + if(!n) return NULL; + ADDHEAD(n, s, LIST_FREE); + SLABSANITYCHECK(SCL_DETAIL); + } + + + SLABSANITYCHECK(SCL_DETAIL); + MOVEHEAD(s, LIST_FREE, LIST_USED); + SLABSANITYCHECK(SCL_DETAIL); + + } + SLABSANITYCHECK(SCL_DETAIL); + + vm_assert(s); + firstused = LH(s, LIST_USED); + vm_assert(firstused); + vm_assert(firstused->sdh.magic == MAGIC); + + for(i = firstused->sdh.freeguess; n < ITEMSPERPAGE(s, bytes); n++, i++) { + SLABSANITYCHECK(SCL_DETAIL); + i = i % ITEMSPERPAGE(s, bytes); + + if(!GETBIT(firstused, i)) { + struct slabdata *f; + char *ret; + SETBIT(firstused, i); + SLABSANITYCHECK(SCL_DETAIL); + if(firstused->sdh.nused == ITEMSPERPAGE(s, bytes)) { + SLABSANITYCHECK(SCL_DETAIL); + MOVEHEAD(s, LIST_USED, LIST_FULL); + SLABSANITYCHECK(SCL_DETAIL); + } + SLABSANITYCHECK(SCL_DETAIL); + ret = ((char *) firstused->data) + i*bytes; + +#if SANITYCHECKS + f = (struct slabdata *) ((char *) ret - (vir_bytes) ret % VM_PAGE_SIZE); + if(f->sdh.magic != MAGIC) { + printf("slaballoc bogus pointer 0x%lx, " + "rounded 0x%lx, bad magic 0x%lx\n", + ret, f, f->sdh.magic); + vm_panic("slaballoc check failed", NO_NUM); + } + *(u32_t *) ret = NOJUNK; +#endif + SLABSANITYCHECK(SCL_FUNCTIONS); + firstused->sdh.freeguess = i+1; + return ret; + } + + SLABSANITYCHECK(SCL_DETAIL); + + } + SLABSANITYCHECK(SCL_FUNCTIONS); + + vm_panic("slaballoc: no space in 'used' slabdata", NO_NUM); + + /* Not reached. */ + return NULL; +} + +/*===========================================================================* + * void *slabfree * + *===========================================================================*/ +PUBLIC void slabfree(void *mem, int bytes) +{ + int i; + struct slabheader *s; + struct slabdata *f; + + SLABSANITYCHECK(SCL_FUNCTIONS); + +#if SANITYCHECKS + if(*(u32_t *) mem == JUNK) { + printf("VM: WARNING: likely double free, JUNK seen\n"); + } +#endif + + /* Retrieve entry in slabs[]. */ + GETSLAB(bytes, s); + + /* Round address down to VM_PAGE_SIZE boundary to get header. */ + f = (struct slabdata *) ((char *) mem - (vir_bytes) mem % VM_PAGE_SIZE); + + vm_assert(f->sdh.magic == MAGIC); + vm_assert(f->sdh.list == LIST_USED || f->sdh.list == LIST_FULL); + + /* Make sure it's in range. */ + vm_assert((char *) mem >= (char *) f->data); + vm_assert((char *) mem < (char *) f->data + sizeof(f->data)); + + /* Get position. */ + i = (char *) mem - (char *) f->data; + vm_assert(!(i % bytes)); + i = i / bytes; + + /* Make sure it _was_ allocated. */ + vm_assert(GETBIT(f, i)); + + /* Free this data. */ + CLEARBIT(f, i); + +#if SANITYCHECKS + *(u32_t *) mem = JUNK; +#endif + + /* Check if this slab changes lists. */ + if(f->sdh.nused == 0) { + /* Now become FREE; must've been USED */ + vm_assert(f->sdh.list == LIST_USED); + UNLINKNODE(f); + if(f == LH(s, LIST_USED)) + LH(s, LIST_USED) = f->sdh.next; + ADDHEAD(f, s, LIST_FREE); + SLABSANITYCHECK(SCL_DETAIL); + } else if(f->sdh.nused == ITEMSPERPAGE(s, bytes)-1) { + /* Now become USED; must've been FULL */ + vm_assert(f->sdh.list == LIST_FULL); + UNLINKNODE(f); + if(f == LH(s, LIST_FULL)) + LH(s, LIST_FULL) = f->sdh.next; + ADDHEAD(f, s, LIST_USED); + SLABSANITYCHECK(SCL_DETAIL); + } else { + /* Stay USED */ + vm_assert(f->sdh.list == LIST_USED); + } + + SLABSANITYCHECK(SCL_FUNCTIONS); + + return; +} + +#if SANITYCHECKS +/*===========================================================================* + * void slabstats * + *===========================================================================*/ +PUBLIC void slabstats(void) +{ + int s, total = 0, totalbytes = 0; + static int n; + n++; + if(n%1000) return; + for(s = 0; s < SLABSIZES; s++) { + int l; + for(l = 0; l < LIST_NUMBER; l++) { + int b, t; + b = s + MINSIZE; + t = checklist(__FILE__, __LINE__, &slabs[s], l, b); + + if(t > 0) { + int bytes = t * b; + printf("VMSTATS: %2d slabs: %d (%dkB)\n", b, t, bytes/1024); + totalbytes += bytes; + } + } + } + + if(pages > 0) { + printf("VMSTATS: %dK net used in slab objects in %d pages (%dkB): %d%% utilization\n", + totalbytes/1024, pages, pages*VM_PAGE_SIZE/1024, + 100 * totalbytes / (pages*VM_PAGE_SIZE)); + } +} +#endif diff --git a/servers/vm/util.h b/servers/vm/util.h new file mode 100644 index 000000000..2b5bd6374 --- /dev/null +++ b/servers/vm/util.h @@ -0,0 +1,28 @@ + +#ifndef _UTIL_H +#define _UTIL_H 1 + +#include "vm.h" +#include "glo.h" + +#define ELEMENTS(a) (sizeof(a)/sizeof((a)[0])) + +#if SANITYCHECKS +#define vm_assert(cond) { \ + if(vm_sanitychecklevel > 0 && !(cond)) { \ + printf("VM:%s:%d: assert failed: %s\n", \ + __FILE__, __LINE__, #cond); \ + panic("VM", "assert failed", NO_NUM); \ + } \ + } +#else +#define vm_assert(cond) ; +#endif + +#define vm_panic(str, n) { char _pline[100]; \ + sprintf(_pline, "%s:%d: %s", __FILE__, __LINE__, (str)); \ + panic("VM", _pline, (n)); \ + } + +#endif + diff --git a/servers/vm/utility.c b/servers/vm/utility.c new file mode 100644 index 000000000..7ddd253bc --- /dev/null +++ b/servers/vm/utility.c @@ -0,0 +1,165 @@ + +/* This file contains some utility routines for VM. */ + +#define _SYSTEM 1 + +#define _MINIX 1 /* To get the brk() prototype (as _brk()). */ +#define brk _brk /* Our brk() must redefine _brk(). */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "proto.h" +#include "glo.h" +#include "util.h" + +#include +#include +#include "../../kernel/const.h" +#include "../../kernel/config.h" +#include "../../kernel/type.h" +#include "../../kernel/proc.h" + +/*===========================================================================* + * get_mem_map * + *===========================================================================*/ +PUBLIC int get_mem_map(proc_nr, mem_map) +int proc_nr; /* process to get map of */ +struct mem_map *mem_map; /* put memory map here */ +{ + struct proc p; + int s; + + if ((s=sys_getproc(&p, proc_nr)) != OK) + return(s); + + memcpy(mem_map, p.p_memmap, sizeof(p.p_memmap)); + return(OK); +} + +/*===========================================================================* + * get_mem_chunks * + *===========================================================================*/ +PUBLIC void get_mem_chunks(mem_chunks) +struct memory *mem_chunks; /* store mem chunks here */ +{ +/* Initialize the free memory list from the 'memory' boot variable. Translate + * the byte offsets and sizes in this list to clicks, properly truncated. + */ + long base, size, limit; + int i; + struct memory *memp; + + /* Obtain and parse memory from system environment. */ + if(env_memory_parse(mem_chunks, NR_MEMS) != OK) + vm_panic("couldn't obtain memory chunks", NO_NUM); + + /* Round physical memory to clicks. Round start up, round end down. */ + for (i = 0; i < NR_MEMS; i++) { + memp = &mem_chunks[i]; /* next mem chunk is stored here */ + base = mem_chunks[i].base; + size = mem_chunks[i].size; + limit = base + size; + base = (base + CLICK_SIZE-1) & ~(long)(CLICK_SIZE-1); + limit &= ~(long)(CLICK_SIZE-1); + if (limit <= base) { + memp->base = memp->size = 0; + } else { + memp->base = base >> CLICK_SHIFT; + memp->size = (limit - base) >> CLICK_SHIFT; + } + } +} + +/*===========================================================================* + * reserve_proc_mem * + *===========================================================================*/ +PUBLIC void reserve_proc_mem(mem_chunks, map_ptr) +struct memory *mem_chunks; /* store mem chunks here */ +struct mem_map *map_ptr; /* memory to remove */ +{ +/* Remove server memory from the free memory list. The boot monitor + * promises to put processes at the start of memory chunks. The + * tasks all use same base address, so only the first task changes + * the memory lists. The servers and init have their own memory + * spaces and their memory will be removed from the list. + */ + struct memory *memp; + for (memp = mem_chunks; memp < &mem_chunks[NR_MEMS]; memp++) { + if (memp->base == map_ptr[T].mem_phys) { + memp->base += map_ptr[T].mem_len + map_ptr[S].mem_vir; + memp->size -= map_ptr[T].mem_len + map_ptr[S].mem_vir; + break; + } + } + if (memp >= &mem_chunks[NR_MEMS]) + { + vm_panic("reserve_proc_mem: can't find map in mem_chunks ", + map_ptr[T].mem_phys); + } +} + +/*===========================================================================* + * vm_isokendpt * + *===========================================================================*/ +PUBLIC int vm_isokendpt(endpoint_t endpoint, int *proc) +{ + *proc = _ENDPOINT_P(endpoint); + if(*proc < -NR_TASKS || *proc >= NR_PROCS) + return EINVAL; + if(*proc >= 0 && endpoint != vmproc[*proc].vm_endpoint) + return EDEADSRCDST; + if(*proc >= 0 && !(vmproc[*proc].vm_flags & VMF_INUSE)) + return EDEADSRCDST; + return OK; +} + + +struct proc mytmpproc; + +/*===========================================================================* + * get_stack_ptr * + *===========================================================================*/ +PUBLIC int get_stack_ptr(proc_nr_e, sp) +int proc_nr_e; /* process to get sp of */ +vir_bytes *sp; /* put stack pointer here */ +{ + int s; + + if ((s=sys_getproc(&mytmpproc, proc_nr_e)) != OK) + return(s); + *sp = mytmpproc.p_reg.sp; + return(OK); +} + +/*===========================================================================* + * _brk * + *===========================================================================*/ +extern char *_brksize; +PUBLIC int brk(brk_addr) +char *brk_addr; +{ + int r; + struct vmproc *vmm = &vmproc[VM_PROC_NR]; + +/* VM wants to call brk() itself. */ + if((r=real_brk(vmm, (vir_bytes) brk_addr)) != OK) + vm_panic("VM: brk() on myself failed\n", NO_NUM); + _brksize = brk_addr; + return 0; +} + diff --git a/servers/vm/vfs.c b/servers/vm/vfs.c new file mode 100644 index 000000000..62f89fea9 --- /dev/null +++ b/servers/vm/vfs.c @@ -0,0 +1,140 @@ + +#define _SYSTEM 1 + +#define VERBOSE 0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "glo.h" +#include "proto.h" +#include "util.h" + +/*===========================================================================* + * register_callback * + *===========================================================================*/ +PRIVATE void register_callback(struct vmproc *for_who, callback_t callback, + int callback_type) +{ + if(for_who->vm_callback) { + vm_panic("register_callback: callback already registered", + for_who->vm_callback_type); + } + for_who->vm_callback = callback; + for_who->vm_callback_type = callback_type; + + return; +} + +/*===========================================================================* + * vfs_open * + *===========================================================================*/ +PUBLIC int vfs_open(struct vmproc *for_who, callback_t callback, + cp_grant_id_t filename_gid, int filename_len, int flags, int mode) +{ + static message m; + int r; + + register_callback(for_who, callback, VM_VFS_REPLY_OPEN); + + m.m_type = VM_VFS_OPEN; + m.VMVO_NAME_GRANT = filename_gid; + m.VMVO_NAME_LENGTH = filename_len; + m.VMVO_FLAGS = flags; + m.VMVO_MODE = mode; + m.VMVO_ENDPOINT = for_who->vm_endpoint; + + if((r=asynsend(VFS_PROC_NR, &m)) != OK) { + vm_panic("vfs_open: asynsend failed", r); + } + + return r; +} + +/*===========================================================================* + * vfs_close * + *===========================================================================*/ +PUBLIC int vfs_close(struct vmproc *for_who, callback_t callback, int fd) +{ + static message m; + int r; + + register_callback(for_who, callback, VM_VFS_REPLY_CLOSE); + + m.m_type = VM_VFS_CLOSE; + m.VMVC_ENDPOINT = for_who->vm_endpoint; + m.VMVC_FD = fd; + + if((r=asynsend(VFS_PROC_NR, &m)) != OK) { + vm_panic("vfs_close: asynsend failed", r); + } + + return r; +} + +/*===========================================================================* + * do_vfs_reply * + *===========================================================================*/ +PUBLIC int do_vfs_reply(message *m) +{ +/* Reply to a request has been received from vfs. Handle it. First verify + * and look up which process, identified by endpoint, this is about. + * Then call the callback function that was registered when the request + * was done. Return result to vfs. + */ + endpoint_t ep; + struct vmproc *vmp; + int procno; + callback_t cb; + ep = m->VMV_ENDPOINT; + if(vm_isokendpt(ep, &procno) != OK) { + printf("VM:do_vfs_reply: reply %d about invalid endpoint %d\n", + m->m_type, ep); + vm_panic("do_vfs_reply: invalid endpoint from vfs", NO_NUM); + } + vmp = &vmproc[procno]; + if(!vmp->vm_callback) { + printf("VM:do_vfs_reply: reply %d: endpoint %d not waiting\n", + m->m_type, ep); + vm_panic("do_vfs_reply: invalid endpoint from vfs", NO_NUM); + } + if(vmp->vm_callback_type != m->m_type) { + printf("VM:do_vfs_reply: reply %d unexpected for endpoint %d\n" + " (expecting %d)\n", m->m_type, ep, vmp->vm_callback_type); + vm_panic("do_vfs_reply: invalid reply from vfs", NO_NUM); + } + if(vmp->vm_flags & VMF_EXITING) { + /* This is not fatal or impossible, but the callback + * function has to realize it shouldn't do any PM or + * VFS calls for this process. + */ + printf("VM:do_vfs_reply: reply %d for EXITING endpoint %d\n", + m->m_type, ep); + } + + /* All desired callback state has been used, so save and reset + * the callback. This allows the callback to register another + * one. + */ + cb = vmp->vm_callback; + vmp->vm_callback = NULL; + cb(vmp, m); + return SUSPEND; +} + diff --git a/servers/vm/vm.h b/servers/vm/vm.h new file mode 100644 index 000000000..323f4a7bb --- /dev/null +++ b/servers/vm/vm.h @@ -0,0 +1,33 @@ + +#define NO_MEM ((phys_clicks) 0) /* returned by alloc_mem() with mem is up */ + +/* Memory flags to pt_allocmap() and alloc_mem(). */ +#define PAF_CLEAR 0x01 /* Clear physical memory. */ +#define PAF_CONTIG 0x02 /* Physically contiguous. */ + +/* special value for v in pt_allocmap */ +#define AM_AUTO ((u32_t) -1) + +#define CLICK2ABS(v) ((v) << CLICK_SHIFT) +#define ABS2CLICK(a) ((a) >> CLICK_SHIFT) + +/* Compile in asserts and custom sanity checks at all? */ +#define SANITYCHECKS 0 +#define VMSTATS 1 + +/* If so, this level: */ +#define SCL_NONE 0 /* No sanity checks - vm_assert()s only. */ +#define SCL_TOP 1 /* Main loop and other high-level places. */ +#define SCL_FUNCTIONS 2 /* Function entry/exit. */ +#define SCL_DETAIL 3 /* Detailled steps. */ +#define SCL_MAX 3 /* Highest value. */ + +/* Type of page allocations. */ +#define VMP_SPARE 0 +#define VMP_PAGETABLE 1 +#define VMP_PAGEDIR 2 +#define VMP_SLAB 3 +#define VMP_CATEGORIES 4 + +/* Flags to pt_writemap(). */ +#define WMF_OVERWRITE 0x01 /* Caller knows map may overwrite. */ diff --git a/servers/vm/vmproc.h b/servers/vm/vmproc.h new file mode 100644 index 000000000..66a83052d --- /dev/null +++ b/servers/vm/vmproc.h @@ -0,0 +1,59 @@ + +#ifndef _VMPROC_H +#define _VMPROC_H 1 + +#include +#include + +#include "vm.h" + +struct vmproc; + +typedef void (*callback_t)(struct vmproc *who, message *m); + +struct vmproc { + struct vm_arch vm_arch; /* architecture-specific data */ + int vm_flags; + endpoint_t vm_endpoint; + pt_t vm_pt; /* page table data, if VMF_HASPT is set */ + vir_bytes vm_stacktop; /* top of stack as seen from process */ + vir_bytes vm_offset; /* offset of addr 0 for process */ + + /* File identification for cs sharing. */ + ino_t vm_ino; /* inode number of file */ + dev_t vm_dev; /* device number of file system */ + time_t vm_ctime; /* inode changed time */ + + /* Regions in virtual address space. */ + struct vir_region *vm_regions; + int vm_count; + + /* Heap for brk() to extend. */ + struct vir_region *vm_heap; + + /* State for requests pending to be done to vfs on behalf of + * this process. + */ + callback_t vm_callback; /* function to call on vfs reply */ + int vm_callback_type; /* expected message type */ + + union { + struct { + cp_grant_id_t gid; + } open; /* VM_VFS_OPEN */ + } vm_state; /* Callback state. */ +#if VMSTATS + int vm_bytecopies; +#endif +}; + +/* Bits for vm_flags */ +#define VMF_INUSE 0x001 /* slot contains a process */ +#define VMF_SEPARATE 0x002 /* separate i&d */ +#define VMF_HASPT 0x004 /* has private page table */ +#define VMF_EXITING 0x008 /* PM is cleaning up this process */ +#define VMF_HAS_DMA 0x010 /* Process directly or indirectly granted + * DMA buffers. + */ + +#endif diff --git a/tools/Makefile b/tools/Makefile index 3b3878623..e0f465a73 100755 --- a/tools/Makefile +++ b/tools/Makefile @@ -15,6 +15,7 @@ PROGRAMS= ../kernel/kernel \ ../drivers/memory/memory \ ../drivers/log/log \ ../servers/mfs/mfs \ + ../servers/vm/vm \ ../servers/init/init usage: