1*45760Sbostic /*-
2*45760Sbostic * Copyright (c) 1986 The Regents of the University of California.
3*45760Sbostic * All rights reserved.
4*45760Sbostic *
5*45760Sbostic * This code is derived from software contributed to Berkeley by
6*45760Sbostic * Computer Consoles Inc.
7*45760Sbostic *
8*45760Sbostic * %sccs.include.redist.c%
9*45760Sbostic *
10*45760Sbostic * @(#)Awriteable.c 7.1 (Berkeley) 12/06/90
11*45760Sbostic */
1229644Ssam
1345699Sbostic #include "align.h"
1429644Ssam
writeable(infop,address,length)1529644Ssam long writeable(infop, address, length)
1629644Ssam process_info *infop;
1729644Ssam long address, length;
1829644Ssam /*
1929644Ssam * Return TRUE (= -1) if the specified bytes can be written without an access
2029644Ssam * control violation (limit and/or protection). Page faults are OK.
2129644Ssam * If problems, return the code that would be pushed by HW on the
2229644Ssam * stack (see the architecture manual).
2329644Ssam * Assumption is that in most cases, access is OK, so a quick 'probew'
2429644Ssam * will be enough. If not, we have to work harder to determine the exact
2529644Ssam * cause and return the right code, without getting the fault here in
2629644Ssam * the kernel !!.
2729644Ssam *
2829644Ssam * The address is assumed to be write for the user.!
2929644Ssam */
3029644Ssam {
3129644Ssam register long Register_12; /* Has to be first reg ! */
3229644Ssam register long Register_11;
3329644Ssam register long Register_10;
3429644Ssam register long Register_9;
3529644Ssam register long Register_8;
3629644Ssam register long subspace;
3729644Ssam register long last_page;
3829644Ssam
3929644Ssam Register_12 = address;
4029644Ssam Register_11 = length-1;
4129644Ssam asm (" probew $1,(r12),$1 "); /* Yeach ... */
4229644Ssam asm (" beql no_access ");
4329644Ssam asm (" addl2 r11,r12 "); /* last byte */
4429644Ssam asm (" probew $1,(r12),$1 ");
4529644Ssam asm (" beql no_access ");
4629644Ssam asm (" movl $-1,r0 "); /* TRUE */
4729644Ssam asm (" ret#1 ");
4829644Ssam asm ("no_access: ");
4929644Ssam /*
5029644Ssam * Now the hard work. Have to check length violation first.
5129644Ssam * If any byte (first or last) causes a length violation, report it as such.
5229644Ssam */
5329644Ssam asm (" mfpr $3,r8 "); /* Get length registers. P0LR */
5429644Ssam asm (" mfpr $5,r9 "); /* P1LR */
5529644Ssam asm (" mfpr $7,r10 "); /* P2LR */
5629644Ssam asm (" mfpr $1,r11 "); /* SLR */
5729644Ssam
5829644Ssam subspace = (address >> 30) & 3;
5929644Ssam Register_12 = (address >> 10) & 0xfffff; /* 1'st byte page # */
6029644Ssam last_page = ( (address+length-1) >> 10) & 0xfffff;
6129644Ssam switch ( subspace ) {
6229644Ssam case 0:
6329644Ssam if ( (Register_12 >= Register_8) ||
6429644Ssam (last_page >= Register_8) ) return (1);
6529644Ssam break;
6629644Ssam case 1:
6729644Ssam if ( (Register_12 >= Register_9) ||
6829644Ssam (last_page >= Register_9) ) return (1);
6929644Ssam break;
7029644Ssam case 2:
7129644Ssam if ( (Register_12 < Register_10) ||
7229644Ssam (last_page < Register_10) ) return (1);
7329644Ssam break;
7429644Ssam case 3:
7529644Ssam if ( (Register_12 >= Register_11) ||
7629644Ssam (last_page >= Register_11) ) return (1);
7729644Ssam break;
7829644Ssam }
7929644Ssam /*
8029644Ssam * OK, it's not a length violation. Must have been an access problem
8129644Ssam * (no write by user).
8229644Ssam *
8329644Ssam * NOTE : I definitely ignore the case of 'no PTE access' since I
8429644Ssam * assume that's not the case for user mode. Besides, the poor
8529644Ssam * guy will just get an access violation that will most probably
8629644Ssam * send him into hyperspace anyway, so no need to be too acurate here.
8729644Ssam */
8829644Ssam return (4);
8929644Ssam }
90