|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 14233 (0x3799) Types: TextFile Notes: UNIX file Names: »seg.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code └─⟦2d53db1df⟧ UNIX Filesystem └─⟦this⟧ »sys/coh/seg.c«
/* (-lgl * The information contained herein is a trade secret of Mark Williams * Company, and is confidential information. It is provided under a * license agreement, and may be copied or disclosed only under the * terms of that agreement. Any reproduction or disclosure of this * material without the express written authorization of Mark Williams * Company or persuant to the license agreement is unlawful. * * COHERENT Version 0.7.3 * Copyright (c) 1982, 1983, 1984. * An unpublished work by Mark Williams Company, Chicago. * All rights reserved. -lgl) */ /* * Coherent. * Segment manipulation. */ #include <coherent.h> #include <buf.h> #include <errno.h> #include <ino.h> #include <inode.h> #include <proc.h> #include <sched.h> #include <seg.h> #include <uproc.h> /* * Initialisation code. */ seginit() { segmq.s_forw = &segmq; segmq.s_back = &segmq; segdq.s_forw = &segdq; segdq.s_back = &segdq; } /* * Given an inode, `ip', and flags, `ff', describing a segment associated * with the inode, see if the segment already exists and if so, return a * copy. If the segment does not exists, allocate the segment having size * `ss', and read the segment using the inode at seek offset `dq' with a * size of `ds'. */ SEG * ssalloc(rp, ip, ff, ss, dq, ds) int *rp; register INODE *ip; size_t ss; size_t dq; size_t ds; { register SEG *sp; register int f; *rp = -1; if (ss == 0) { *rp = 1; return (NULL); } lock(seglink); f = ff & (SFSHRX|SFTEXT); /* * Look for the segment in the memory queue. */ for (sp=segmq.s_forw; sp!=&segmq; sp=sp->s_forw) { if (sp->s_ip==ip && (sp->s_flags&(SFSHRX|SFTEXT))==f) { unlock(seglink); sp = segdupl(sp); segfinm(sp); *rp = 1; return (sp); } } /* * Look for the segment on the disk queue. */ for (sp=segdq.s_forw; sp!=&segdq; sp=sp->s_forw) { if (sp->s_ip==ip && (sp->s_flags&(SFSHRX|SFTEXT))==f) { unlock(seglink); sp = segdupl(sp); segfinm(sp); *rp = 1; return (sp); } } unlock(seglink); /* * Allocate and create the segment. */ if ((sp=salloc(ss, ff)) == NULL) return (NULL); if (exsread(sp, ip, ds, dq, (size_t)0) == 0) return (NULL); if ((ff&SFSHRX) != 0) { sp->s_ip = ip; ip->i_refc++; } *rp = 0; return (sp); } /* * Given a pointer to a newly created process, copy all of our segments * into the given process. */ segadup(cpp) register PROC *cpp; { register SEG *sp; register int n; register PROC *pp; pp = SELF; cpp->p_flags |= PFSWIO; for (n=0; n<NUSEG; n++) { if ((sp=pp->p_segp[n]) == NULL) continue; if ((sp=segdupl(sp)) == NULL) break; cpp->p_segp[n] = sp; if ((sp->s_flags&SFCORE) == 0) cpp->p_flags &= ~PFCORE; } if (n < NUSEG) { while (n > 0) { if ((sp=cpp->p_segp[--n]) != NULL) { sfree(sp); cpp->p_segp[n] = NULL; } } } cpp->p_flags &= ~PFSWIO; return (n); } /* * Duplicate a segment. */ SEG * segdupl(sp) register SEG *sp; { register SEG *sp1; register size_t ss; if ((sp->s_flags&SFSHRX) != 0) { sp->s_urefc++; sp->s_lrefc++; return (sp); } ss = ctob((size_t)sp->s_size); if ((sp->s_flags&SFCORE) == 0) panic("Cannot duplicate non shared swapped segment"); if ((sp1=salloc(ss, sp->s_flags|SFNSWP|SFNCLR)) == NULL) sp1 = segdupd(sp); else { sp1->s_flags = sp->s_flags; slrcopy(sp->s_mbase, sp1->s_mbase, sp->s_size); } return (sp1); } /* * Allocate a segment `n' bytes long. `f' contains some pseudo flags. */ SEG * salloc(n, f) size_t n; { register SEG *sp; register saddr_t s; register int r; r = (f&(SFSYST|SFHIGH|SFTEXT|SFSHRX|SFDOWN)) | SFCORE; s = btocru(n); lock(seglink); sp = sxalloc(s, f); unlock(seglink); if (sp != NULL) sp->s_flags = r; else { if ((f&SFNSWP) != 0) return (NULL); if ((sp=kalloc(sizeof(SEG))) == NULL) return (NULL); sp->s_forw = sp; sp->s_back = sp; sp->s_flags = r; sp->s_urefc = 1; sp->s_lrefc = 1; if (segsext(sp, s) == NULL) { kfree(sp); return (NULL); } } if ((f&SFNCLR) == 0) sclear(sp->s_mbase, s); return (sp); } /* * Free the given segment pointer. */ sfree(sp) register SEG *sp; { register INODE *ip; --sp->s_lrefc; if (--sp->s_urefc == 0) { if (sp->s_lrefc != 0) panic("Bad segment count"); if ((ip=sp->s_ip) != NULL) ldetach(ip); lock(seglink); sp->s_back->s_forw = sp->s_forw; sp->s_forw->s_back = sp->s_back; unlock(seglink); kfree(sp); } } /* * Grow or shrink the segment `sp' so that it has size `n'. */ seggrow(sp, n) register SEG *sp; size_t n; { register SEG *sp1; register saddr_t s; register saddr_t d; register saddr_t pb; register saddr_t nb; register int dowflag; dowflag = sp->s_flags&SFDOWN; s = btocru(n); /* * Size of new segment is smaller or the same size as the old * segment. */ lock(seglink); d = s - sp->s_size; if (s <= sp->s_size) { if (dowflag) sp->s_mbase -= d; sp->s_size = s; unlock(seglink); return (1); } if ((sp1=sp->s_back) == &segmq) pb = corebot; else pb = sp1->s_mbase + sp1->s_size; if ((sp1=sp->s_forw) == &segmq) nb = coretop; else nb = sp1->s_mbase; /* * If the segment does not grow down, see if there is enough * space after the segment. */ if (dowflag==0 && nb-sp->s_mbase>=s) { sclear(sp->s_mbase+sp->s_size, d); sp->s_size = s; unlock(seglink); return (1); } /* * If the segment grows down, see if there is enough space * before the segment. */ if (dowflag!=0 && sp->s_mbase+sp->s_size-pb>=s) { sp->s_mbase -= d; sp->s_size = s; sclear(sp->s_mbase, d); unlock(seglink); return (1); } /* * Is there enough space in total counting the gaps on either * side of us? */ if (nb-pb >= s) { if (dowflag == 0) { slrcopy(sp->s_mbase, pb, sp->s_size); sclear(pb+sp->s_size, d); sp->s_mbase = pb; } else { srlcopy(sp->s_mbase, nb-sp->s_size, sp->s_size); sclear(nb-s, d); sp->s_mbase = nb-s; } sp->s_size = s; unlock(seglink); return (1); } /* * Try to allocate a segment somewhere else on the segment queue * and copy ourselves there. */ unlock(seglink); if ((sp1=salloc(ctob((size_t)s), sp->s_flags|SFNSWP|SFNCLR)) != NULL) { if (dowflag == 0) { slrcopy(sp->s_mbase, sp1->s_mbase, sp->s_size); sclear(sp1->s_mbase+sp->s_size, d); } else { slrcopy(sp->s_mbase, sp1->s_mbase+d, sp->s_size); sclear(sp1->s_mbase, d); } lock(seglink); satcopy(sp, sp1); unlock(seglink); return (1); } /* * Last chance. Extend the segment by swapping it. */ if (segsext(sp, s) != NULL) { if (dowflag == 0) sclear(sp->s_mbase+s-d, d); else { srlcopy(sp->s_mbase, sp->s_mbase+d, s-d); sclear(sp->s_mbase, d); } return (1); } /* * At least we tried. */ return (0); } /* * Given a segment pointer, `sp' and a segment size, grow the given segment * to the given size. */ segsize(sp, s2) register SEG *sp; vaddr_t s2; { register vaddr_t s1; s1 = (vaddr_t)ctob(sp->s_size); if (seggrow(sp, (size_t)s2) == 0) { u.u_error = ENOMEM; return; } if (sproto() == 0) if (seggrow(sp, (size_t)s1)==0 || sproto()==0) sendsig(SIGSEGV, SELF); segload(); } /* * Grow the segment `sp1' to the size `s' by swapping it out * and back in. The segment may not be locked. */ SEG * segsext(sp1, s) register SEG *sp1; register saddr_t s; { register SEG *sp2; #ifndef NOMONITOR if (swmflag) printf("Segsext(%p, %u)\n", SELF, SELF->p_pid); #endif if (sexflag == 0) { u.u_error = ENOMEM; return (NULL); } lock(seglink); if ((sp2=sdalloc(s)) == NULL) { unlock(seglink); return (NULL); } unlock(seglink); sp1->s_lrefc++; if (sp1->s_size != 0) swapio(1, sp1->s_mbase, sp2->s_dbase, sp1->s_size); lock(seglink); satcopy(sp1, sp2); unlock(seglink); sp1->s_flags &= ~SFCORE; --sp1->s_lrefc; segfinm(sp1); return (sp1); } /* * Force the given segment to be in memory. One can only force * one segment to be in memory at a time. */ segfinm(sp) register SEG *sp; { register PROC *pp; register int s; if ((sp->s_flags&SFCORE) != 0) return; pp = SELF; pp->p_segp[SIAUXIL] = sp; pp->p_flags &= ~PFCORE; s = sphi(); setrun(pp); dispatch(); spl(s); pp->p_segp[SIAUXIL] = NULL; } /* * Make a copy of the segment `sp1' which is in memory by writing * it out to disk. */ SEG * segdupd(sp1) register SEG *sp1; { register SEG *sp2; if (sexflag == 0) return (NULL); lock(seglink); if ((sp2=sdalloc(sp1->s_size)) == NULL) { unlock(seglink); return (NULL); } sp1->s_lrefc++; unlock(seglink); swapio(1, sp1->s_mbase, sp2->s_dbase, sp1->s_size); --sp1->s_lrefc; sp2->s_ip = sp1->s_ip; sp2->s_flags = sp1->s_flags & ~SFCORE; sp2->s_size = sp1->s_size; return (sp2); } /* * Given a flag, a core address in clicks, a disk address and a count in * clicks, perform an I/O operation between core and disk. If `flag' is * set, the transfer is to the disk otherwise it is to memory. As you may * have guessed, this is used by the swapper. */ swapio(f, c, d, n) saddr_t c; daddr_t d; saddr_t n; { register BUF *bp; register int s; register int nb; #ifndef NOMONITOR if (swmflag > 1) printf("swapio(%s,%x,%x,%x)\n",(f?"out":"in"),c,(int)d,n); #endif if (d < swapbot || d+stod(n) > swaptop || c < corebot || c+n > coretop) panic("Swapio bad parameter"); bp = &swapbuf; lock(bp->b_gate); SELF->p_flags |= PFSWIO; while (n != 0) { nb = (n > btocrd(SCHUNK)) ? SCHUNK : ctob(n); bp->b_flag = BFNTP; bp->b_req = f ? BWRITE : BREAD; bp->b_dev = swapdev; bp->b_bno = d; bp->b_paddr = ctob((paddr_t)c); bp->b_count = nb; s = sphi(); dblock(swapdev, bp); while ((bp->b_flag&BFNTP) != 0) sleep((char *)bp, CVBLKIO, IVBLKIO, SVBLKIO); spl(s); if ((bp->b_flag&BFERR) != 0) panic("Swapio error"); c += btocrd(SCHUNK); d += stod(btocrd(SCHUNK)); n -= btocrd(nb); } unlock(bp->b_gate); SELF->p_flags &= ~PFSWIO; } /* * Make the segment descriptor pointed to by `sp1' have the attributes * of `sp2' including it's position in the segment queue and release * `sp2'. `seglink' must be locked when this routine is called. */ satcopy(sp1, sp2) register SEG *sp1; register SEG *sp2; { sp1->s_back->s_forw = sp1->s_forw; sp1->s_forw->s_back = sp1->s_back; sp2->s_back->s_forw = sp1; sp1->s_back = sp2->s_back; sp2->s_forw->s_back = sp1; sp1->s_forw = sp2->s_forw; sp1->s_size = sp2->s_size; sp1->s_mbase = sp2->s_mbase; sp1->s_dbase = sp2->s_dbase; kfree(sp2); } /* * Allocate a segment on disk that is `n' clicks long. * The `seglink' gate should be locked before this routine is called. */ SEG * sdalloc(s) saddr_t s; { register SEG *sp1; register SEG *sp2; register daddr_t d; register daddr_t d1; register daddr_t d2; d = stod(s); d1 = swapbot; sp1 = &segdq; do { if (d1 >= swaptop) return (NULL); if ((sp1=sp1->s_forw) != &segdq) d2 = sp1->s_dbase; else d2 = swaptop; if (d2-d1 >= d) { if ((sp2=kalloc(sizeof(SEG))) == NULL) return (NULL); sp1->s_back->s_forw = sp2; sp2->s_back = sp1->s_back; sp1->s_back = sp2; sp2->s_forw = sp1; sp2->s_urefc = 1; sp2->s_lrefc = 1; sp2->s_size = s; sp2->s_dbase = d1; return (sp2); } d1 = sp1->s_dbase + stod(sp1->s_size); } while (sp1 != &segdq); return (NULL); } /* * Allocate a segment in memory that is `n' clicks long. * The `seglink' gate should be locked before this routine is called. */ SEG * smalloc(s) saddr_t s; { register SEG *sp1; register SEG *sp2; register saddr_t s1; register saddr_t s2; s1 = corebot; sp1 = &segmq; do { if ((sp1=sp1->s_forw) != &segmq) s2 = sp1->s_mbase; else s2 = coretop; if (s2-s1 >= s) { if ((sp2=kalloc(sizeof (SEG))) == NULL) return (NULL); sp1->s_back->s_forw = sp2; sp2->s_back = sp1->s_back; sp1->s_back = sp2; sp2->s_forw = sp1; sp2->s_urefc = 1; sp2->s_lrefc = 1; sp2->s_size = s; sp2->s_mbase = s1; return (sp2); } s1 = sp1->s_mbase + sp1->s_size; } while (sp1 != &segmq); return (NULL); } /* * Allocate a segment from the high end of memory that is `n' clicks long. * The `seglink' gate should be locked before this routine is called. */ SEG * shalloc(s) saddr_t s; { register SEG *sp1; register SEG *sp2; register saddr_t s1; register saddr_t s2; sp1 = &segmq; s2 = coretop; do { if ((sp1=sp1->s_back) != &segmq) s1 = sp1->s_mbase + sp1->s_size; else s1 = corebot; if (s2-s1 >= s) { if ((sp2=kalloc(sizeof (SEG))) == NULL) return (NULL); sp1->s_forw->s_back = sp2; sp2->s_forw = sp1->s_forw; sp1->s_forw = sp2; sp2->s_back = sp1; sp2->s_urefc = 1; sp2->s_lrefc = 1; sp2->s_size = s; sp2->s_mbase = s2-s; return (sp2); } s2 = sp1->s_mbase; } while (sp1 != &segmq); return (NULL); } /* * Set up `SR' structure in user area from segments descriptors in * process structure. Also set up the user segmentation registers. */ sproto() { register int n; register SEG *sp; register SR *srp; register PROC *pp; pp = SELF; kclear(u.u_segl, sizeof(u.u_segl)); for (n=0; n<NUSEG; n++) { if ((sp=pp->p_segp[n]) == NULL) continue; srp = &u.u_segl[n]; if (n == SIUSERP) srp->sr_base = &u; else srp->sr_flag |= SRFPMAP; if (n!=SISTEXT && n!=SISDATA) srp->sr_flag |= SRFDUMP; if (n!=SIUSERP && n!=SISTEXT && n!=SIPTEXT) srp->sr_flag |= SRFDATA; srp->sr_size = ctob(sp->s_size); srp->sr_segp = sp; } pp->p_flags &= ~PFSPROTO; return (mproto()); } /* * Segment consistency checks for the paranoid. segchk() { register SEG *sp; register saddr_t s; register daddr_t d; register int nbad; nbad = 0; sp = &segmq; s = corebot; while ((sp=sp->s_forw) != &segmq) { if (sp->s_mbase < s) nbad += badseg("mem", sp->s_mbase, 0); s = sp->s_mbase + sp->s_size; } if (coretop < s) nbad += badseg("mem", sp->s_back->s_mbase, sp->s_back->s_size); sp = &segdq; d = swapbot; while ((sp=sp->s_forw) != &segdq) { if (sp->s_dbase < d) nbad += badseg("disk", (int)sp->s_dbase, 0); d = sp->s_dbase + stod(sp->s_size); } if (swaptop < d) nbad += badseg("disk", (int)sp->s_back->s_dbase, sp->s_back->s_size); } badseg(t, b, s) char *t; int b, s; { printf("Bad %s segment %x for %x clicks\n", t, b, s); return (1); } */