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