changelog shortlog tags branches files raw gz bz2 help

Mercurial > hg > plan9front / changeset: bcm64: switch to 64k page size

changeset 7244: 2e8af1bf191d
parent 7243: 34f64dcbbc25
child 7245: f21df6c00920
author: cinap_lenrek@felloff.net
date: Fri, 17 May 2019 18:35:14 +0200
files: sys/src/9/bcm64/dat.h sys/src/9/bcm64/l.s sys/src/9/bcm64/mem.h sys/src/9/bcm64/mkfile sys/src/9/bcm64/mmu.c sys/src/9/port/rebootcmd.c
description: bcm64: switch to 64k page size
     1.1--- a/sys/src/9/bcm64/dat.h
     1.2+++ b/sys/src/9/bcm64/dat.h
     1.3@@ -115,7 +115,7 @@ struct Conf
     1.4  */
     1.5 struct MMMU
     1.6 {
     1.7-	PTE*	mmul1;		/* l1 for this processor */
     1.8+	PTE*	mmutop;		/* first level user page table */
     1.9 };
    1.10 
    1.11 /*
    1.12@@ -245,8 +245,6 @@ struct Soc {			/* SoC dependent configur
    1.13 	uintptr	busdram;
    1.14 	uintptr	busio;
    1.15 	uintptr	armlocal;
    1.16-	u32int	l1ptedramattrs;
    1.17-	u32int	l2ptedramattrs;
    1.18 };
    1.19 extern Soc soc;
    1.20 
     2.1--- a/sys/src/9/bcm64/l.s
     2.2+++ b/sys/src/9/bcm64/l.s
     2.3@@ -195,8 +195,8 @@ TEXT mmuenable<>(SB), 1, $-4
     2.4 	/* T0SZ */	| (64-EVASHIFT)<<0 )
     2.5 	MOV	$TCRINIT, R1
     2.6 	MRS	ID_AA64MMFR0_EL1, R2
     2.7-	ANDW	$0xF, R2	// IPS
     2.8-	ADD	R2<<32, R1
     2.9+	ANDW	$0x7, R2	// PARange
    2.10+	ADD	R2<<32, R1	// IPS
    2.11 	MSR	R1, TCR_EL1
    2.12 	ISB	$SY
    2.13 
     3.1--- a/sys/src/9/bcm64/mem.h
     3.2+++ b/sys/src/9/bcm64/mem.h
     3.3@@ -17,11 +17,11 @@
     3.4  *	16K	32M	64G	128T
     3.5  *	64K	512M	4T	-
     3.6  */
     3.7-#define	PGSHIFT		12		/* log(BY2PG) */
     3.8+#define	PGSHIFT		16		/* log(BY2PG) */
     3.9 #define	BY2PG		(1ULL<<PGSHIFT)	/* bytes per page */
    3.10 
    3.11 /* effective virtual address space */
    3.12-#define EVASHIFT	36
    3.13+#define EVASHIFT	33
    3.14 #define EVAMASK		((1ULL<<EVASHIFT)-1)
    3.15 
    3.16 #define PTSHIFT		(PGSHIFT-3)
    3.17@@ -31,8 +31,8 @@
    3.18 
    3.19 #define PTL1X(v, l)	(L1TABLEX(v, l) | PTLX(v, l))
    3.20 #define L1TABLEX(v, l)	(L1TABLE(v, l) << PTSHIFT)
    3.21-#define L1TABLES	HOWMANY(-KZERO, PGLSZ(2))
    3.22-#define L1TABLE(v, l)	(L1TABLES-1 - ((PTLX(v, 2) % L1TABLES) >> (((l)-1)*PTSHIFT)) + (l)-1)
    3.23+#define L1TABLES	HOWMANY(-KSEG0, PGLSZ(2))
    3.24+#define L1TABLE(v, l)	(L1TABLES - ((PTLX(v, 2) % L1TABLES) >> (((l)-1)*PTSHIFT)) + (l)-1)
    3.25 #define L1TOPSIZE	(1ULL << (EVASHIFT - PTLEVELS*PTSHIFT))
    3.26 
    3.27 #define	MAXMACH		4			/* max # cpus system can run */
    3.28@@ -42,14 +42,12 @@
    3.29 #define STACKALIGN(sp)	((sp) & ~7)		/* bug: assure with alloc */
    3.30 #define TRAPFRAMESIZE	(38*8)
    3.31 
    3.32-/*
    3.33- * Address spaces.
    3.34- * KTZERO is used by kprof and dumpstack (if any).
    3.35- *
    3.36- * KZERO is mapped to physical 0 (start of ram).
    3.37- */
    3.38-
    3.39-#define	KZERO		0xFFFFFFFF80000000ULL	/* kernel address space */
    3.40+#define KSEG0		(0xFFFFFFFF00000000ULL)
    3.41+#define VIRTIO		(0xFFFFFFFF3F000000ULL)	/* i/o registers */
    3.42+#define	ARMLOCAL	(0xFFFFFFFF40000000ULL)
    3.43+#define	KZERO		(0xFFFFFFFF80000000ULL)	/* kernel address space */
    3.44+#define FRAMEBUFFER	(0xFFFFFFFFC0000000ULL|PTEWT)
    3.45+#define	VGPIO		0			/* virtual gpio for pi3 ACT LED */
    3.46 
    3.47 #define SPINTABLE	(KZERO+0xd8)
    3.48 #define CONFADDR	(KZERO+0x100)
    3.49@@ -57,16 +55,12 @@
    3.50 #define	VCBUFFER	(KZERO+0x3400)		/* videocore mailbox buffer */
    3.51 
    3.52 #define L1		(L1TOP-L1SIZE)
    3.53-#define L1SIZE		((L1TABLES+PTLEVELS-3)*BY2PG)
    3.54+#define L1SIZE		((L1TABLES+PTLEVELS-2)*BY2PG)
    3.55 #define L1TOP		((MACHADDR(MAXMACH-1)-L1TOPSIZE)&-BY2PG)
    3.56 
    3.57 #define MACHADDR(n)	(KTZERO-((n)+1)*MACHSIZE)
    3.58 
    3.59 #define	KTZERO		(KZERO+0x80000)		/* kernel text start */
    3.60-#define FRAMEBUFFER	(0xFFFFFFFFC0000000ULL | PTEWT)
    3.61-#define VIRTIO		0xFFFFFFFFE0000000ULL	/* i/o registers */
    3.62-#define	ARMLOCAL	(VIRTIO+IOSIZE)
    3.63-#define	VGPIO		0			/* virtual gpio for pi3 ACT LED */
    3.64 
    3.65 #define	UZERO		0ULL			/* user segment */
    3.66 #define	UTZERO		(UZERO+0x10000)		/* user text start */
     4.1--- a/sys/src/9/bcm64/mkfile
     4.2+++ b/sys/src/9/bcm64/mkfile
     4.3@@ -71,11 +71,11 @@ 9:V: $p$CONF s$p$CONF
     4.4 $p$CONF:DQ:	$CONF.c $OBJ $LIB mkfile
     4.5 	$CC $CFLAGS '-DKERNDATE='`{date -n} $CONF.c
     4.6 	echo '# linking raw kernel'	# H6: no headers, data segment aligned
     4.7-	$LD -l -o $target -H6 -R4096 -T$loadaddr $OBJ $CONF.$O $LIB
     4.8+	$LD -l -o $target -H6 -R0x10000 -T$loadaddr $OBJ $CONF.$O $LIB
     4.9 
    4.10 s$p$CONF:DQ:	$CONF.$O $OBJ $LIB
    4.11 	echo '# linking kernel with symbols'
    4.12-	$LD -l -o $target -R4096 -T$loadaddr $OBJ $CONF.$O $LIB
    4.13+	$LD -l -o $target -R0x10000 -T$loadaddr $OBJ $CONF.$O $LIB
    4.14 	size $target
    4.15 
    4.16 $p$CONF.gz:D:	$p$CONF
     5.1--- a/sys/src/9/bcm64/mmu.c
     5.2+++ b/sys/src/9/bcm64/mmu.c
     5.3@@ -8,45 +8,65 @@
     5.4 void
     5.5 mmu0init(uintptr *l1)
     5.6 {
     5.7-	uintptr va, pa, pe;
     5.8+	uintptr va, pa, pe, attr;
     5.9 
    5.10-	/* 0 identity map */
    5.11+	/* KZERO */
    5.12+	attr = PTEWRITE | PTEAF | PTEKERNEL | PTESH(SHARE_INNER);
    5.13 	pe = PHYSDRAM + soc.dramsize;
    5.14 	if(pe > (uintptr)-KZERO)
    5.15 		pe = (uintptr)-KZERO;
    5.16-
    5.17-	for(pa = PHYSDRAM; pa < pe; pa += PGLSZ(1))
    5.18-		l1[PTL1X(pa, 1)] = pa | PTEVALID | PTEBLOCK | PTEWRITE | PTEAF
    5.19-			 | PTEKERNEL | PTESH(SHARE_INNER);
    5.20+	for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(1), va += PGLSZ(1)){
    5.21+		if(pe - pa < PGLSZ(1)){
    5.22+			l1[PTL1X(va, 1)] = (uintptr)l1 | PTEVALID | PTETABLE;
    5.23+			l1[PTL1X(pa, 1)] = (uintptr)l1 | PTEVALID | PTETABLE;
    5.24+			for(; pa < pe; pa += PGLSZ(0), va += PGLSZ(0))
    5.25+				l1[PTLX(va, 0)] = pa | PTEVALID | PTEPAGE | attr;
    5.26+			break;
    5.27+		}
    5.28+		l1[PTL1X(va, 1)] = pa | PTEVALID | PTEBLOCK | attr;
    5.29+		l1[PTL1X(pa, 1)] = pa | PTEVALID | PTEBLOCK | attr;
    5.30+	}
    5.31+	pe = (uintptr)-KZERO;	/* populate top levels for mmukmap() */
    5.32 	if(PTLEVELS > 2)
    5.33-	for(pa = PHYSDRAM; pa < pe; pa += PGLSZ(2))
    5.34+	for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(2), va += PGLSZ(2)){
    5.35+		l1[PTL1X(va, 2)] = (uintptr)&l1[L1TABLEX(va, 1)] | PTEVALID | PTETABLE;
    5.36 		l1[PTL1X(pa, 2)] = (uintptr)&l1[L1TABLEX(pa, 1)] | PTEVALID | PTETABLE;
    5.37+	}
    5.38 	if(PTLEVELS > 3)
    5.39-	for(pa = PHYSDRAM; pa < pe; pa += PGLSZ(3))
    5.40+	for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(3), va += PGLSZ(3)){
    5.41+		l1[PTL1X(va, 3)] = (uintptr)&l1[L1TABLEX(va, 2)] | PTEVALID | PTETABLE;
    5.42 		l1[PTL1X(pa, 3)] = (uintptr)&l1[L1TABLEX(pa, 2)] | PTEVALID | PTETABLE;
    5.43-
    5.44-	/* KZERO */
    5.45-	for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(1), va += PGLSZ(1))
    5.46-		l1[PTL1X(va, 1)] = pa | PTEVALID | PTEBLOCK | PTEWRITE | PTEAF
    5.47-			| PTEKERNEL | PTESH(SHARE_INNER);
    5.48-	if(PTLEVELS > 2)
    5.49-	for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(2), va += PGLSZ(2))
    5.50-		l1[PTL1X(va, 2)] = (uintptr)&l1[L1TABLEX(va, 1)] | PTEVALID | PTETABLE;
    5.51-	if(PTLEVELS > 3)
    5.52-	for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(3), va += PGLSZ(3))
    5.53-		l1[PTL1X(va, 3)] = (uintptr)&l1[L1TABLEX(va, 2)] | PTEVALID | PTETABLE;
    5.54+	}
    5.55 
    5.56 	/* VIRTIO */
    5.57-	pe = -VIRTIO + soc.physio;
    5.58-	for(pa = soc.physio, va = VIRTIO; pa < pe; pa += PGLSZ(1), va += PGLSZ(1))
    5.59-		l1[PTL1X(va, 1)] = pa | PTEVALID | PTEBLOCK | PTEWRITE | PTEAF
    5.60-			| PTEKERNEL | PTESH(SHARE_OUTER) | PTEDEVICE;
    5.61+	attr = PTEWRITE | PTEAF | PTEKERNEL | PTESH(SHARE_OUTER) | PTEDEVICE;
    5.62+	pe = soc.physio + IOSIZE;
    5.63+	for(pa = soc.physio, va = VIRTIO; pa < pe; pa += PGLSZ(1), va += PGLSZ(1)){
    5.64+		if(pe - pa < PGLSZ(1)){
    5.65+			l1[PTL1X(va, 1)] = (uintptr)l1 | PTEVALID | PTETABLE;
    5.66+			for(; pa < pe; pa += PGLSZ(0), va += PGLSZ(0))
    5.67+				l1[PTLX(va, 0)] = pa | PTEVALID | PTEPAGE | attr;
    5.68+			break;
    5.69+		}
    5.70+		l1[PTL1X(va, 1)] = pa | PTEVALID | PTEBLOCK | attr;
    5.71+	}
    5.72 	if(PTLEVELS > 2)
    5.73 	for(pa = soc.physio, va = VIRTIO; pa < pe; pa += PGLSZ(2), va += PGLSZ(2))
    5.74 		l1[PTL1X(va, 2)] = (uintptr)&l1[L1TABLEX(va, 1)] | PTEVALID | PTETABLE;
    5.75 	if(PTLEVELS > 3)
    5.76 	for(pa = soc.physio, va = VIRTIO; pa < pe; pa += PGLSZ(3), va += PGLSZ(3))
    5.77 		l1[PTL1X(va, 3)] = (uintptr)&l1[L1TABLEX(va, 2)] | PTEVALID | PTETABLE;
    5.78+
    5.79+	/* ARMLOCAL */
    5.80+	pe = soc.armlocal + MB;
    5.81+	for(pa = soc.armlocal, va = ARMLOCAL; pa < pe; pa += PGLSZ(1), va += PGLSZ(1))
    5.82+		l1[PTL1X(va, 1)] = pa | PTEVALID | PTEBLOCK | attr;
    5.83+	if(PTLEVELS > 2)
    5.84+	for(pa = soc.armlocal, va = ARMLOCAL; pa < pe; pa += PGLSZ(2), va += PGLSZ(2))
    5.85+		l1[PTL1X(va, 2)] = (uintptr)&l1[L1TABLEX(va, 1)] | PTEVALID | PTETABLE;
    5.86+	if(PTLEVELS > 3)
    5.87+	for(pa = soc.armlocal, va = ARMLOCAL; pa < pe; pa += PGLSZ(3), va += PGLSZ(3))
    5.88+		l1[PTL1X(va, 3)] = (uintptr)&l1[L1TABLEX(va, 2)] | PTEVALID | PTETABLE;
    5.89 }
    5.90 
    5.91 void
    5.92@@ -57,21 +77,17 @@ mmu0clear(uintptr *l1)
    5.93 	pe = PHYSDRAM + soc.dramsize;
    5.94 	if(pe > (uintptr)-KZERO)
    5.95 		pe = (uintptr)-KZERO;
    5.96-
    5.97-	for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(1), va += PGLSZ(1)){
    5.98+	for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(1), va += PGLSZ(1))
    5.99 		if(PTL1X(pa, 1) != PTL1X(va, 1))
   5.100 			l1[PTL1X(pa, 1)] = 0;
   5.101-	}
   5.102 	if(PTLEVELS > 2)
   5.103-	for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(2), va += PGLSZ(2)){
   5.104+	for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(2), va += PGLSZ(2))
   5.105 		if(PTL1X(pa, 2) != PTL1X(va, 2))
   5.106 			l1[PTL1X(pa, 2)] = 0;
   5.107-	}
   5.108 	if(PTLEVELS > 3)
   5.109-	for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(3), va += PGLSZ(3)){
   5.110+	for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(3), va += PGLSZ(3))
   5.111 		if(PTL1X(pa, 3) != PTL1X(va, 3))
   5.112 			l1[PTL1X(pa, 3)] = 0;
   5.113-	}
   5.114 }
   5.115 
   5.116 void
   5.117@@ -85,32 +101,24 @@ mmuidmap(uintptr *l1)
   5.118 	pe = PHYSDRAM + soc.dramsize;
   5.119 	if(pe > (uintptr)-KZERO)
   5.120 		pe = (uintptr)-KZERO;
   5.121-
   5.122-	for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(1), va += PGLSZ(1)){
   5.123-		if(PTL1X(pa, 1) != PTL1X(va, 1))
   5.124-			l1[PTL1X(pa, 1)] = pa | PTEVALID | PTEBLOCK | PTEWRITE | PTEAF
   5.125-				 | PTEKERNEL | PTESH(SHARE_INNER);
   5.126-	}
   5.127+	for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(1), va += PGLSZ(1))
   5.128+		l1[PTL1X(pa, 1)] = l1[PTL1X(va, 1)];
   5.129 	if(PTLEVELS > 2)
   5.130-	for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(2), va += PGLSZ(2)){
   5.131-		if(PTL1X(pa, 2) != PTL1X(va, 2))
   5.132-			l1[PTL1X(pa, 2)] = PADDR(&l1[L1TABLEX(pa, 1)]) | PTEVALID | PTETABLE;
   5.133-	}
   5.134+	for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(2), va += PGLSZ(2))
   5.135+		l1[PTL1X(pa, 2)] = l1[PTL1X(va, 2)];
   5.136 	if(PTLEVELS > 3)
   5.137-	for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(3), va += PGLSZ(3)){
   5.138-		if(PTL1X(pa, 3) != PTL1X(va, 3))
   5.139-			l1[PTL1X(pa, 3)] = PADDR(&l1[L1TABLEX(pa, 2)]) | PTEVALID | PTETABLE;
   5.140-	}
   5.141+	for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(3), va += PGLSZ(3))
   5.142+		l1[PTL1X(pa, 3)] = l1[PTL1X(va, 3)];
   5.143 	setttbr(PADDR(&l1[L1TABLEX(0, PTLEVELS-1)]));
   5.144 }
   5.145 
   5.146 void
   5.147 mmu1init(void)
   5.148 {
   5.149-	m->mmul1 = mallocalign(L1SIZE+L1TOPSIZE, BY2PG, L1SIZE, 0);
   5.150-	if(m->mmul1 == nil)
   5.151-		panic("mmu1init: no memory for mmul1");
   5.152-	memset(m->mmul1, 0, L1SIZE+L1TOPSIZE);
   5.153+	m->mmutop = mallocalign(L1TOPSIZE, BY2PG, 0, 0);
   5.154+	if(m->mmutop == nil)
   5.155+		panic("mmu1init: no memory for mmutop");
   5.156+	memset(m->mmutop, 0, L1TOPSIZE);
   5.157 	mmuswitch(nil);
   5.158 }
   5.159 
   5.160@@ -187,7 +195,7 @@ mmuwalk(uintptr va, int level)
   5.161 	int i, x;
   5.162 
   5.163 	x = PTLX(va, PTLEVELS-1);
   5.164-	table = &m->mmul1[L1TABLEX(va, PTLEVELS-1)];
   5.165+	table = m->mmutop;
   5.166 	for(i = PTLEVELS-2; i >= level; i--){
   5.167 		pte = table[x];
   5.168 		if(pte & PTEVALID) {
   5.169@@ -262,12 +270,12 @@ putasid(Proc *p)
   5.170 {
   5.171 	/*
   5.172 	 * Prevent the following scenario:
   5.173-	 *	pX sleeps on cpuA, leaving its page tables in mmul1
   5.174+	 *	pX sleeps on cpuA, leaving its page tables in mmutop
   5.175 	 *	pX wakes up on cpuB, and exits, freeing its page tables
   5.176 	 *  pY on cpuB allocates a freed page table page and overwrites with data
   5.177 	 *  cpuA takes an interrupt, and is now running with bad page tables
   5.178 	 * In theory this shouldn't hurt because only user address space tables
   5.179-	 * are affected, and mmuswitch will clear mmul1 before a user process is
   5.180+	 * are affected, and mmuswitch will clear mmutop before a user process is
   5.181 	 * dispatched.  But empirically it correlates with weird problems, eg
   5.182 	 * resetting of the core clock at 0x4000001C which confuses local timers.
   5.183 	 */
   5.184@@ -287,7 +295,6 @@ putmmu(uintptr va, uintptr pa, Page *pg)
   5.185 	s = splhi();
   5.186 	while((pte = mmuwalk(va, 0)) == nil){
   5.187 		spllo();
   5.188-		assert(up->mmufree == nil);
   5.189 		up->mmufree = newpage(0, nil, 0);
   5.190 		splhi();
   5.191 	}
   5.192@@ -330,10 +337,10 @@ mmuswitch(Proc *p)
   5.193 	Page *t;
   5.194 
   5.195 	for(va = UZERO; va < USTKTOP; va += PGLSZ(PTLEVELS-1))
   5.196-		m->mmul1[PTL1X(va, PTLEVELS-1)] = 0;
   5.197+		m->mmutop[PTLX(va, PTLEVELS-1)] = 0;
   5.198 
   5.199 	if(p == nil){
   5.200-		setttbr(PADDR(&m->mmul1[L1TABLEX(0, PTLEVELS-1)]));
   5.201+		setttbr(PADDR(m->mmutop));
   5.202 		return;
   5.203 	}
   5.204 
   5.205@@ -344,13 +351,13 @@ mmuswitch(Proc *p)
   5.206 
   5.207 	for(t = p->mmuhead[PTLEVELS-1]; t != nil; t = t->next){
   5.208 		va = t->va;
   5.209-		m->mmul1[PTL1X(va, PTLEVELS-1)] = t->pa | PTEVALID | PTETABLE;
   5.210+		m->mmutop[PTLX(va, PTLEVELS-1)] = t->pa | PTEVALID | PTETABLE;
   5.211 	}
   5.212 
   5.213 	if(allocasid(p))
   5.214 		flushasid((uvlong)p->asid<<48);
   5.215 
   5.216-	setttbr((uvlong)p->asid<<48 | PADDR(&m->mmul1[L1TABLEX(0, PTLEVELS-1)]));
   5.217+	setttbr((uvlong)p->asid<<48 | PADDR(m->mmutop));
   5.218 }
   5.219 
   5.220 void
     6.1--- a/sys/src/9/port/rebootcmd.c
     6.2+++ b/sys/src/9/port/rebootcmd.c
     6.3@@ -37,7 +37,7 @@ rebootcmd(int argc, char *argv[])
     6.4 {
     6.5 	Chan *c;
     6.6 	Exec exec;
     6.7-	ulong magic, text, rtext, entry, data, size;
     6.8+	ulong magic, text, rtext, entry, data, size, align;
     6.9 	uchar *p;
    6.10 
    6.11 	if(argc == 0)
    6.12@@ -68,8 +68,17 @@ rebootcmd(int argc, char *argv[])
    6.13 	if(magic & HDR_MAGIC)
    6.14 		readn(c, &exec, 8);
    6.15 
    6.16+	switch(magic){
    6.17+	case R_MAGIC:
    6.18+		align = 0x10000;	/* 64k segment alignment for arm64 */
    6.19+		break;
    6.20+	default:
    6.21+		align = BY2PG;
    6.22+		break;
    6.23+	}
    6.24+
    6.25 	/* round text out to page boundary */
    6.26-	rtext = PGROUND(entry+text)-entry;
    6.27+	rtext = ROUND(entry+text, align)-entry;
    6.28 	size = rtext + data;
    6.29 	p = malloc(size);
    6.30 	if(p == nil)