19ef1f84bSDavid du Colombier #include "u.h"
29ef1f84bSDavid du Colombier #include "../port/lib.h"
39ef1f84bSDavid du Colombier #include "mem.h"
49ef1f84bSDavid du Colombier #include "dat.h"
59ef1f84bSDavid du Colombier #include "fns.h"
69ef1f84bSDavid du Colombier #include "../port/error.h"
79ef1f84bSDavid du Colombier
89ef1f84bSDavid du Colombier int
fault(uintptr addr,int read)99ef1f84bSDavid du Colombier fault(uintptr addr, int read)
109ef1f84bSDavid du Colombier {
119ef1f84bSDavid du Colombier Segment *s;
129ef1f84bSDavid du Colombier char *sps;
13*094d6818SDavid du Colombier int i, color;
149ef1f84bSDavid du Colombier
15406c76faSDavid du Colombier if(up == nil)
16406c76faSDavid du Colombier panic("fault: nil up");
179ef1f84bSDavid du Colombier if(up->nlocks)
18406c76faSDavid du Colombier print("fault: addr %#p: nlocks %d\n", addr, up->nlocks);
199ef1f84bSDavid du Colombier
209ef1f84bSDavid du Colombier sps = up->psstate;
219ef1f84bSDavid du Colombier up->psstate = "Fault";
229ef1f84bSDavid du Colombier spllo();
239ef1f84bSDavid du Colombier
249ef1f84bSDavid du Colombier m->pfault++;
25*094d6818SDavid du Colombier for(i = 0;; i++) {
269ef1f84bSDavid du Colombier s = seg(up, addr, 1); /* leaves s->lk qlocked if seg != nil */
274498a243SDavid du Colombier if(s == nil) {
289ef1f84bSDavid du Colombier up->psstate = sps;
299ef1f84bSDavid du Colombier return -1;
309ef1f84bSDavid du Colombier }
319ef1f84bSDavid du Colombier
329ef1f84bSDavid du Colombier if(!read && (s->type&SG_RONLY)) {
339ef1f84bSDavid du Colombier qunlock(&s->lk);
349ef1f84bSDavid du Colombier up->psstate = sps;
359ef1f84bSDavid du Colombier return -1;
369ef1f84bSDavid du Colombier }
379ef1f84bSDavid du Colombier
38*094d6818SDavid du Colombier color = s->color;
39*094d6818SDavid du Colombier if(i > 3)
40*094d6818SDavid du Colombier color = -1;
41*094d6818SDavid du Colombier if(fixfault(s, addr, read, 1, color) == 0) /* qunlocks s->lk */
429ef1f84bSDavid du Colombier break;
439ef1f84bSDavid du Colombier
449ef1f84bSDavid du Colombier /*
459ef1f84bSDavid du Colombier * See the comment in newpage that describes
469ef1f84bSDavid du Colombier * how to get here.
479ef1f84bSDavid du Colombier */
489ef1f84bSDavid du Colombier }
499ef1f84bSDavid du Colombier
509ef1f84bSDavid du Colombier up->psstate = sps;
519ef1f84bSDavid du Colombier return 0;
529ef1f84bSDavid du Colombier }
539ef1f84bSDavid du Colombier
549ef1f84bSDavid du Colombier static void
faulterror(char * s,Chan * c,int freemem)559ef1f84bSDavid du Colombier faulterror(char *s, Chan *c, int freemem)
569ef1f84bSDavid du Colombier {
579ef1f84bSDavid du Colombier char buf[ERRMAX];
589ef1f84bSDavid du Colombier
599ef1f84bSDavid du Colombier if(c && c->path){
609ef1f84bSDavid du Colombier snprint(buf, sizeof buf, "%s accessing %s: %s", s, c->path->s, up->errstr);
619ef1f84bSDavid du Colombier s = buf;
629ef1f84bSDavid du Colombier }
639ef1f84bSDavid du Colombier if(up->nerrlab) {
649ef1f84bSDavid du Colombier postnote(up, 1, s, NDebug);
659ef1f84bSDavid du Colombier error(s);
669ef1f84bSDavid du Colombier }
679ef1f84bSDavid du Colombier pexit(s, freemem);
689ef1f84bSDavid du Colombier }
699ef1f84bSDavid du Colombier
70406c76faSDavid du Colombier void (*checkaddr)(ulong, Segment *, Page *);
71406c76faSDavid du Colombier ulong addr2check;
72406c76faSDavid du Colombier
739ef1f84bSDavid du Colombier int
fixfault(Segment * s,uintptr addr,int read,int dommuput,int color)74*094d6818SDavid du Colombier fixfault(Segment *s, uintptr addr, int read, int dommuput, int color)
759ef1f84bSDavid du Colombier {
769ef1f84bSDavid du Colombier int type;
779ef1f84bSDavid du Colombier int ref;
789ef1f84bSDavid du Colombier Pte **p, *etp;
799ef1f84bSDavid du Colombier Page **pg, *lkp, *new;
809ef1f84bSDavid du Colombier Page *(*fn)(Segment*, uintptr);
819ef1f84bSDavid du Colombier uintptr mmuphys, pgsize, soff;
829ef1f84bSDavid du Colombier
8357fe3081SDavid du Colombier pgsize = segpgsize(s);
849ef1f84bSDavid du Colombier addr &= ~(pgsize-1);
859ef1f84bSDavid du Colombier soff = addr-s->base;
869ef1f84bSDavid du Colombier p = &s->map[soff/s->ptemapmem];
874498a243SDavid du Colombier if(*p == nil)
889ef1f84bSDavid du Colombier *p = ptealloc();
899ef1f84bSDavid du Colombier
909ef1f84bSDavid du Colombier etp = *p;
919ef1f84bSDavid du Colombier pg = &etp->pages[(soff&(s->ptemapmem-1))>>s->lg2pgsize];
929ef1f84bSDavid du Colombier type = s->type&SG_TYPE;
939ef1f84bSDavid du Colombier
949ef1f84bSDavid du Colombier if(pg < etp->first)
959ef1f84bSDavid du Colombier etp->first = pg;
969ef1f84bSDavid du Colombier if(pg > etp->last)
979ef1f84bSDavid du Colombier etp->last = pg;
989ef1f84bSDavid du Colombier
999ef1f84bSDavid du Colombier mmuphys = 0;
1009ef1f84bSDavid du Colombier switch(type) {
1019ef1f84bSDavid du Colombier default:
1029ef1f84bSDavid du Colombier panic("fault");
1039ef1f84bSDavid du Colombier break;
1049ef1f84bSDavid du Colombier
1059ef1f84bSDavid du Colombier case SG_TEXT: /* Demand load */
1069ef1f84bSDavid du Colombier if(pagedout(*pg))
107*094d6818SDavid du Colombier pio(s, addr, soff, pg, color);
1089ef1f84bSDavid du Colombier
1099ef1f84bSDavid du Colombier mmuphys = PPN((*pg)->pa) | PTERONLY|PTEVALID;
1109ef1f84bSDavid du Colombier (*pg)->modref = PG_REF;
1119ef1f84bSDavid du Colombier break;
1129ef1f84bSDavid du Colombier
1139ef1f84bSDavid du Colombier case SG_BSS:
1149ef1f84bSDavid du Colombier case SG_SHARED: /* Zero fill on demand */
1159ef1f84bSDavid du Colombier case SG_STACK:
1164498a243SDavid du Colombier if(*pg == nil) {
117*094d6818SDavid du Colombier new = newpage(1, s, addr, s->lg2pgsize, color, 1);
1189ef1f84bSDavid du Colombier if(new == nil)
1199ef1f84bSDavid du Colombier return -1;
1209ef1f84bSDavid du Colombier
1219ef1f84bSDavid du Colombier *pg = new;
1229ef1f84bSDavid du Colombier }
1239ef1f84bSDavid du Colombier goto common;
1249ef1f84bSDavid du Colombier
1259ef1f84bSDavid du Colombier case SG_DATA:
1269ef1f84bSDavid du Colombier common: /* Demand load/pagein/copy on write */
1279ef1f84bSDavid du Colombier if(pagedout(*pg))
128*094d6818SDavid du Colombier pio(s, addr, soff, pg, color);
1299ef1f84bSDavid du Colombier
1309ef1f84bSDavid du Colombier /*
1319ef1f84bSDavid du Colombier * It's only possible to copy on write if
1329ef1f84bSDavid du Colombier * we're the only user of the segment.
1339ef1f84bSDavid du Colombier */
1349ef1f84bSDavid du Colombier if(read && sys->copymode == 0 && s->ref == 1) {
1359ef1f84bSDavid du Colombier mmuphys = PPN((*pg)->pa)|PTERONLY|PTEVALID;
1369ef1f84bSDavid du Colombier (*pg)->modref |= PG_REF;
1379ef1f84bSDavid du Colombier break;
1389ef1f84bSDavid du Colombier }
1399ef1f84bSDavid du Colombier
1409ef1f84bSDavid du Colombier lkp = *pg;
1419ef1f84bSDavid du Colombier lock(lkp);
1429ef1f84bSDavid du Colombier
1439ef1f84bSDavid du Colombier ref = lkp->ref;
1449ef1f84bSDavid du Colombier if(ref <= 0)
1459ef1f84bSDavid du Colombier panic("fault: page->ref %d <= 0", ref);
1469ef1f84bSDavid du Colombier
1479ef1f84bSDavid du Colombier if(ref == 1 && lkp->image != nil){
1489ef1f84bSDavid du Colombier duppage(lkp);
1499ef1f84bSDavid du Colombier ref = lkp->ref;
1509ef1f84bSDavid du Colombier }
1519ef1f84bSDavid du Colombier unlock(lkp);
1529ef1f84bSDavid du Colombier
1539ef1f84bSDavid du Colombier if(ref > 1) {
154*094d6818SDavid du Colombier new = newpage(0, s, addr, s->lg2pgsize, color, 1);
1559ef1f84bSDavid du Colombier if(new == nil)
1569ef1f84bSDavid du Colombier return -1;
1579ef1f84bSDavid du Colombier *pg = new;
1589ef1f84bSDavid du Colombier copypage(lkp, *pg);
1599ef1f84bSDavid du Colombier putpage(lkp);
1609ef1f84bSDavid du Colombier }
1619ef1f84bSDavid du Colombier mmuphys = PPN((*pg)->pa) | PTEWRITE | PTEVALID;
1629ef1f84bSDavid du Colombier (*pg)->modref = PG_MOD|PG_REF;
1639ef1f84bSDavid du Colombier break;
1649ef1f84bSDavid du Colombier
1659ef1f84bSDavid du Colombier case SG_PHYSICAL:
1664498a243SDavid du Colombier if(*pg == nil) {
1679ef1f84bSDavid du Colombier fn = s->pseg->pgalloc;
1689ef1f84bSDavid du Colombier if(fn)
1699ef1f84bSDavid du Colombier *pg = (*fn)(s, addr);
1709ef1f84bSDavid du Colombier else {
1719ef1f84bSDavid du Colombier new = smalloc(sizeof(Page));
1729ef1f84bSDavid du Colombier new->va = addr;
1739ef1f84bSDavid du Colombier new->pa = s->pseg->pa+(addr-s->base);
1749ef1f84bSDavid du Colombier new->ref = 1;
1759ef1f84bSDavid du Colombier new->lg2size = s->pseg->lg2pgsize;
1769ef1f84bSDavid du Colombier if(new->lg2size == 0)
1779ef1f84bSDavid du Colombier new->lg2size = PGSHFT; /* TO DO */
1789ef1f84bSDavid du Colombier *pg = new;
1799ef1f84bSDavid du Colombier }
1809ef1f84bSDavid du Colombier }
1819ef1f84bSDavid du Colombier
182406c76faSDavid du Colombier if (checkaddr && addr == addr2check)
183406c76faSDavid du Colombier (*checkaddr)(addr, s, *pg);
1841247705eSDavid du Colombier mmuphys = PPN((*pg)->pa) | PTEVALID;
1851247705eSDavid du Colombier if((s->pseg->attr & SG_RONLY) == 0)
1861247705eSDavid du Colombier mmuphys |= PTEWRITE;
1871247705eSDavid du Colombier if((s->pseg->attr & SG_CACHED) == 0)
1881247705eSDavid du Colombier mmuphys |= PTEUNCACHED;
1899ef1f84bSDavid du Colombier (*pg)->modref = PG_MOD|PG_REF;
1909ef1f84bSDavid du Colombier break;
1919ef1f84bSDavid du Colombier }
1929ef1f84bSDavid du Colombier qunlock(&s->lk);
1939ef1f84bSDavid du Colombier
1949ef1f84bSDavid du Colombier if(dommuput)
1959ef1f84bSDavid du Colombier mmuput(addr, mmuphys, *pg);
1969ef1f84bSDavid du Colombier
1979ef1f84bSDavid du Colombier return 0;
1989ef1f84bSDavid du Colombier }
1999ef1f84bSDavid du Colombier
2009ef1f84bSDavid du Colombier void
pio(Segment * s,uintptr addr,uintptr soff,Page ** p,int color)201*094d6818SDavid du Colombier pio(Segment *s, uintptr addr, uintptr soff, Page **p, int color)
2029ef1f84bSDavid du Colombier {
2039ef1f84bSDavid du Colombier Page *new;
2049ef1f84bSDavid du Colombier KMap *k;
2059ef1f84bSDavid du Colombier Chan *c;
2069ef1f84bSDavid du Colombier int n, ask;
2079ef1f84bSDavid du Colombier char *kaddr;
2089ef1f84bSDavid du Colombier ulong daddr;
2099ef1f84bSDavid du Colombier Page *loadrec;
2109ef1f84bSDavid du Colombier uintptr pgsize;
2119ef1f84bSDavid du Colombier
21257fe3081SDavid du Colombier pgsize = segpgsize(s);
2139ef1f84bSDavid du Colombier loadrec = *p;
2149ef1f84bSDavid du Colombier if(!pagedout(*p) || loadrec != nil)
2159ef1f84bSDavid du Colombier return;
2169ef1f84bSDavid du Colombier /* demand load from a text/data image */
2179ef1f84bSDavid du Colombier daddr = s->fstart+soff;
2189ef1f84bSDavid du Colombier new = lookpage(s->image, daddr);
2199ef1f84bSDavid du Colombier if(new != nil) {
2209ef1f84bSDavid du Colombier *p = new;
2219ef1f84bSDavid du Colombier return;
2229ef1f84bSDavid du Colombier }
2239ef1f84bSDavid du Colombier
2249ef1f84bSDavid du Colombier c = s->image->c;
2259ef1f84bSDavid du Colombier ask = s->flen-soff;
2269ef1f84bSDavid du Colombier if(ask > pgsize)
2279ef1f84bSDavid du Colombier ask = pgsize;
2289ef1f84bSDavid du Colombier qunlock(&s->lk);
2299ef1f84bSDavid du Colombier
230*094d6818SDavid du Colombier new = newpage(0, s, addr, s->lg2pgsize, color, 0);
2319ef1f84bSDavid du Colombier if(new == nil)
2329ef1f84bSDavid du Colombier panic("pio"); /* can't happen, s wasn't locked */
2339ef1f84bSDavid du Colombier
2349ef1f84bSDavid du Colombier k = kmap(new);
2359ef1f84bSDavid du Colombier kaddr = (char*)VA(k);
2369ef1f84bSDavid du Colombier
2379ef1f84bSDavid du Colombier while(waserror()) {
2389ef1f84bSDavid du Colombier if(strcmp(up->errstr, Eintr) == 0)
2399ef1f84bSDavid du Colombier continue;
2409ef1f84bSDavid du Colombier kunmap(k);
2419ef1f84bSDavid du Colombier putpage(new);
2429ef1f84bSDavid du Colombier faulterror(Eioload, c, 0);
2439ef1f84bSDavid du Colombier }
2449ef1f84bSDavid du Colombier
2459ef1f84bSDavid du Colombier n = c->dev->read(c, kaddr, ask, daddr);
2469ef1f84bSDavid du Colombier if(n != ask)
2479ef1f84bSDavid du Colombier faulterror(Eioload, c, 0);
2489ef1f84bSDavid du Colombier if(ask < pgsize)
2499ef1f84bSDavid du Colombier memset(kaddr+ask, 0, pgsize-ask);
2509ef1f84bSDavid du Colombier
2519ef1f84bSDavid du Colombier poperror();
2529ef1f84bSDavid du Colombier kunmap(k);
2539ef1f84bSDavid du Colombier
2549ef1f84bSDavid du Colombier qlock(&s->lk);
2559ef1f84bSDavid du Colombier /*
2569ef1f84bSDavid du Colombier * race, another proc may have read the page in while
2579ef1f84bSDavid du Colombier * s->lk was unlocked
2589ef1f84bSDavid du Colombier */
2599ef1f84bSDavid du Colombier if(*p == nil) {
2609ef1f84bSDavid du Colombier new->daddr = daddr;
2619ef1f84bSDavid du Colombier cachepage(new, s->image);
2629ef1f84bSDavid du Colombier *p = new;
2639ef1f84bSDavid du Colombier }
2649ef1f84bSDavid du Colombier else
2659ef1f84bSDavid du Colombier putpage(new);
2669ef1f84bSDavid du Colombier
2679ef1f84bSDavid du Colombier if(s->flushme)
2680d74731bSDavid du Colombier mmucachectl(*p, PG_TXTFLUSH);
2699ef1f84bSDavid du Colombier }
2709ef1f84bSDavid du Colombier
2719ef1f84bSDavid du Colombier /*
2729ef1f84bSDavid du Colombier * Called only in a system call
2739ef1f84bSDavid du Colombier */
2749ef1f84bSDavid du Colombier int
okaddr(uintptr addr,long len,int write)2759ef1f84bSDavid du Colombier okaddr(uintptr addr, long len, int write)
2769ef1f84bSDavid du Colombier {
2779ef1f84bSDavid du Colombier Segment *s;
2789ef1f84bSDavid du Colombier
2799c621cc8SDavid du Colombier /* second test is paranoia only needed on 64-bit systems */
2809c621cc8SDavid du Colombier if(len >= 0 && addr+len >= addr)
2819c621cc8SDavid du Colombier while ((s = seg(up, addr, 0)) != nil &&
2829c621cc8SDavid du Colombier (!write || !(s->type&SG_RONLY))) {
2839c621cc8SDavid du Colombier if(addr+len <= s->top)
2849c621cc8SDavid du Colombier return 1;
2859ef1f84bSDavid du Colombier len -= s->top - addr;
2869ef1f84bSDavid du Colombier addr = s->top;
2879ef1f84bSDavid du Colombier }
2889ef1f84bSDavid du Colombier return 0;
2899ef1f84bSDavid du Colombier }
2909ef1f84bSDavid du Colombier
2919ef1f84bSDavid du Colombier void*
validaddr(void * addr,long len,int write)2929ef1f84bSDavid du Colombier validaddr(void* addr, long len, int write)
2939ef1f84bSDavid du Colombier {
2949ef1f84bSDavid du Colombier if(!okaddr(PTR2UINT(addr), len, write)){
2959ef1f84bSDavid du Colombier pprint("suicide: invalid address %#p/%ld in sys call pc=%#p\n",
2969ef1f84bSDavid du Colombier addr, len, userpc(nil));
2979ef1f84bSDavid du Colombier pexit("Suicide", 0);
2989ef1f84bSDavid du Colombier }
2999ef1f84bSDavid du Colombier
3009ef1f84bSDavid du Colombier return UINT2PTR(addr);
3019ef1f84bSDavid du Colombier }
3029ef1f84bSDavid du Colombier
3039ef1f84bSDavid du Colombier /*
3049ef1f84bSDavid du Colombier * &s[0] is known to be a valid address.
3059ef1f84bSDavid du Colombier */
3069ef1f84bSDavid du Colombier void*
vmemchr(void * s,int c,int n)3079ef1f84bSDavid du Colombier vmemchr(void *s, int c, int n)
3089ef1f84bSDavid du Colombier {
3099ef1f84bSDavid du Colombier int r;
3109ef1f84bSDavid du Colombier uintptr a;
3119ef1f84bSDavid du Colombier void *t;
3129ef1f84bSDavid du Colombier
3139ef1f84bSDavid du Colombier a = PTR2UINT(s);
3149ef1f84bSDavid du Colombier while(ROUNDUP(a, PGSZ) != ROUNDUP(a+n-1, PGSZ)){
3159ef1f84bSDavid du Colombier /* spans pages; handle this page */
3169ef1f84bSDavid du Colombier r = PGSZ - (a & (PGSZ-1));
3179ef1f84bSDavid du Colombier t = memchr(UINT2PTR(a), c, r);
3189ef1f84bSDavid du Colombier if(t)
3199ef1f84bSDavid du Colombier return t;
3209ef1f84bSDavid du Colombier a += r;
3219ef1f84bSDavid du Colombier n -= r;
322fe56f827SDavid du Colombier if(!iskaddr(a))
3239ef1f84bSDavid du Colombier validaddr(UINT2PTR(a), 1, 0);
3249ef1f84bSDavid du Colombier }
3259ef1f84bSDavid du Colombier
3269ef1f84bSDavid du Colombier /* fits in one page */
3279ef1f84bSDavid du Colombier return memchr(UINT2PTR(a), c, n);
3289ef1f84bSDavid du Colombier }
3299ef1f84bSDavid du Colombier
3309ef1f84bSDavid du Colombier Segment*
seg(Proc * p,uintptr addr,int dolock)3319ef1f84bSDavid du Colombier seg(Proc *p, uintptr addr, int dolock)
3329ef1f84bSDavid du Colombier {
3339ef1f84bSDavid du Colombier Segment **s, **et, *n;
3349ef1f84bSDavid du Colombier
3359ef1f84bSDavid du Colombier et = &p->seg[NSEG];
3369ef1f84bSDavid du Colombier for(s = p->seg; s < et; s++) {
3379ef1f84bSDavid du Colombier n = *s;
3384498a243SDavid du Colombier if(n == nil)
3399ef1f84bSDavid du Colombier continue;
3409ef1f84bSDavid du Colombier if(addr >= n->base && addr < n->top) {
3419ef1f84bSDavid du Colombier if(dolock == 0)
3429ef1f84bSDavid du Colombier return n;
3439ef1f84bSDavid du Colombier
3449ef1f84bSDavid du Colombier qlock(&n->lk);
3459ef1f84bSDavid du Colombier if(addr >= n->base && addr < n->top)
3469ef1f84bSDavid du Colombier return n;
3479ef1f84bSDavid du Colombier qunlock(&n->lk);
3489ef1f84bSDavid du Colombier }
3499ef1f84bSDavid du Colombier }
3509ef1f84bSDavid du Colombier
3519ef1f84bSDavid du Colombier return 0;
3529ef1f84bSDavid du Colombier }
3531f646f47SDavid du Colombier
3541f646f47SDavid du Colombier extern void checkmmu(uintptr, uintmem);
3551f646f47SDavid du Colombier void
checkpages(void)3561f646f47SDavid du Colombier checkpages(void)
3571f646f47SDavid du Colombier {
3581f646f47SDavid du Colombier int checked;
3591f646f47SDavid du Colombier uintptr addr, off;
3601f646f47SDavid du Colombier Pte *p;
3611f646f47SDavid du Colombier Page *pg;
3621f646f47SDavid du Colombier Segment **sp, **ep, *s;
3631f646f47SDavid du Colombier uint pgsize;
3641f646f47SDavid du Colombier
3651f646f47SDavid du Colombier if(up == nil)
3661f646f47SDavid du Colombier return;
3671f646f47SDavid du Colombier
3681f646f47SDavid du Colombier checked = 0;
3691f646f47SDavid du Colombier for(sp=up->seg, ep=&up->seg[NSEG]; sp<ep; sp++){
3701f646f47SDavid du Colombier s = *sp;
3711f646f47SDavid du Colombier if(s == nil)
3721f646f47SDavid du Colombier continue;
3731f646f47SDavid du Colombier qlock(&s->lk);
37457fe3081SDavid du Colombier pgsize = segpgsize(s);
3751f646f47SDavid du Colombier for(addr=s->base; addr<s->top; addr+=pgsize){
3761f646f47SDavid du Colombier off = addr - s->base;
3771f646f47SDavid du Colombier p = s->map[off/s->ptemapmem];
3781f646f47SDavid du Colombier if(p == nil)
3791f646f47SDavid du Colombier continue;
3801f646f47SDavid du Colombier pg = p->pages[(off&(s->ptemapmem-1))/pgsize];
3811f646f47SDavid du Colombier if(pg == nil || pagedout(pg))
3821f646f47SDavid du Colombier continue;
3831f646f47SDavid du Colombier checkmmu(addr, pg->pa);
3841f646f47SDavid du Colombier checked++;
3851f646f47SDavid du Colombier }
3861f646f47SDavid du Colombier qunlock(&s->lk);
3871f646f47SDavid du Colombier }
3881f646f47SDavid du Colombier print("%d %s: checked %d page table entries\n", up->pid, up->text, checked);
3891f646f47SDavid du Colombier }
390