Path: blob/master/arch/alpha/lib/strncpy_from_user.S
10817 views
/*1* arch/alpha/lib/strncpy_from_user.S2* Contributed by Richard Henderson ([email protected])3*4* Just like strncpy except in the return value:5*6* -EFAULT if an exception occurs before the terminator is copied.7* N if the buffer filled.8*9* Otherwise the length of the string is returned.10*/111213#include <asm/errno.h>14#include <asm/regdef.h>151617/* Allow an exception for an insn; exit if we get one. */18#define EX(x,y...) \1999: x,##y; \20.section __ex_table,"a"; \21.long 99b - .; \22lda $31, $exception-99b($0); \23.previous242526.set noat27.set noreorder28.text2930.globl __strncpy_from_user31.ent __strncpy_from_user32.frame $30, 0, $2633.prologue 03435.align 336$aligned:37/* On entry to this basic block:38t0 == the first destination word for masking back in39t1 == the first source word. */4041/* Create the 1st output word and detect 0's in the 1st input word. */42lda t2, -1 # e1 : build a mask against false zero43mskqh t2, a1, t2 # e0 : detection in the src word44mskqh t1, a1, t3 # e0 :45ornot t1, t2, t2 # .. e1 :46mskql t0, a1, t0 # e0 : assemble the first output word47cmpbge zero, t2, t8 # .. e1 : bits set iff null found48or t0, t3, t0 # e0 :49beq a2, $a_eoc # .. e1 :50bne t8, $a_eos # .. e1 :5152/* On entry to this basic block:53t0 == a source word not containing a null. */5455$a_loop:56stq_u t0, 0(a0) # e0 :57addq a0, 8, a0 # .. e1 :58EX( ldq_u t0, 0(a1) ) # e0 :59addq a1, 8, a1 # .. e1 :60subq a2, 1, a2 # e0 :61cmpbge zero, t0, t8 # .. e1 (stall)62beq a2, $a_eoc # e1 :63beq t8, $a_loop # e1 :6465/* Take care of the final (partial) word store. At this point66the end-of-count bit is set in t8 iff it applies.6768On entry to this basic block we have:69t0 == the source word containing the null70t8 == the cmpbge mask that found it. */7172$a_eos:73negq t8, t12 # e0 : find low bit set74and t8, t12, t12 # e1 (stall)7576/* For the sake of the cache, don't read a destination word77if we're not going to need it. */78and t12, 0x80, t6 # e0 :79bne t6, 1f # .. e1 (zdb)8081/* We're doing a partial word store and so need to combine82our source and original destination words. */83ldq_u t1, 0(a0) # e0 :84subq t12, 1, t6 # .. e1 :85or t12, t6, t8 # e0 :86unop #87zapnot t0, t8, t0 # e0 : clear src bytes > null88zap t1, t8, t1 # .. e1 : clear dst bytes <= null89or t0, t1, t0 # e1 :90911: stq_u t0, 0(a0)92br $finish_up9394/* Add the end-of-count bit to the eos detection bitmask. */95$a_eoc:96or t10, t8, t897br $a_eos9899/*** The Function Entry Point ***/100.align 3101__strncpy_from_user:102mov a0, v0 # save the string start103beq a2, $zerolength104105/* Are source and destination co-aligned? */106xor a0, a1, t1 # e0 :107and a0, 7, t0 # .. e1 : find dest misalignment108and t1, 7, t1 # e0 :109addq a2, t0, a2 # .. e1 : bias count by dest misalignment110subq a2, 1, a2 # e0 :111and a2, 7, t2 # e1 :112srl a2, 3, a2 # e0 : a2 = loop counter = (count - 1)/8113addq zero, 1, t10 # .. e1 :114sll t10, t2, t10 # e0 : t10 = bitmask of last count byte115bne t1, $unaligned # .. e1 :116117/* We are co-aligned; take care of a partial first word. */118119EX( ldq_u t1, 0(a1) ) # e0 : load first src word120addq a1, 8, a1 # .. e1 :121122beq t0, $aligned # avoid loading dest word if not needed123ldq_u t0, 0(a0) # e0 :124br $aligned # .. e1 :125126127/* The source and destination are not co-aligned. Align the destination128and cope. We have to be very careful about not reading too much and129causing a SEGV. */130131.align 3132$u_head:133/* We know just enough now to be able to assemble the first134full source word. We can still find a zero at the end of it135that prevents us from outputting the whole thing.136137On entry to this basic block:138t0 == the first dest word, unmasked139t1 == the shifted low bits of the first source word140t6 == bytemask that is -1 in dest word bytes */141142EX( ldq_u t2, 8(a1) ) # e0 : load second src word143addq a1, 8, a1 # .. e1 :144mskql t0, a0, t0 # e0 : mask trailing garbage in dst145extqh t2, a1, t4 # e0 :146or t1, t4, t1 # e1 : first aligned src word complete147mskqh t1, a0, t1 # e0 : mask leading garbage in src148or t0, t1, t0 # e0 : first output word complete149or t0, t6, t6 # e1 : mask original data for zero test150cmpbge zero, t6, t8 # e0 :151beq a2, $u_eocfin # .. e1 :152bne t8, $u_final # e1 :153154lda t6, -1 # e1 : mask out the bits we have155mskql t6, a1, t6 # e0 : already seen156stq_u t0, 0(a0) # e0 : store first output word157or t6, t2, t2 # .. e1 :158cmpbge zero, t2, t8 # e0 : find nulls in second partial159addq a0, 8, a0 # .. e1 :160subq a2, 1, a2 # e0 :161bne t8, $u_late_head_exit # .. e1 :162163/* Finally, we've got all the stupid leading edge cases taken care164of and we can set up to enter the main loop. */165166extql t2, a1, t1 # e0 : position hi-bits of lo word167EX( ldq_u t2, 8(a1) ) # .. e1 : read next high-order source word168addq a1, 8, a1 # e0 :169cmpbge zero, t2, t8 # e1 (stall)170beq a2, $u_eoc # e1 :171bne t8, $u_eos # e1 :172173/* Unaligned copy main loop. In order to avoid reading too much,174the loop is structured to detect zeros in aligned source words.175This has, unfortunately, effectively pulled half of a loop176iteration out into the head and half into the tail, but it does177prevent nastiness from accumulating in the very thing we want178to run as fast as possible.179180On entry to this basic block:181t1 == the shifted high-order bits from the previous source word182t2 == the unshifted current source word183184We further know that t2 does not contain a null terminator. */185186.align 3187$u_loop:188extqh t2, a1, t0 # e0 : extract high bits for current word189addq a1, 8, a1 # .. e1 :190extql t2, a1, t3 # e0 : extract low bits for next time191addq a0, 8, a0 # .. e1 :192or t0, t1, t0 # e0 : current dst word now complete193EX( ldq_u t2, 0(a1) ) # .. e1 : load high word for next time194stq_u t0, -8(a0) # e0 : save the current word195mov t3, t1 # .. e1 :196subq a2, 1, a2 # e0 :197cmpbge zero, t2, t8 # .. e1 : test new word for eos198beq a2, $u_eoc # e1 :199beq t8, $u_loop # e1 :200201/* We've found a zero somewhere in the source word we just read.202If it resides in the lower half, we have one (probably partial)203word to write out, and if it resides in the upper half, we204have one full and one partial word left to write out.205206On entry to this basic block:207t1 == the shifted high-order bits from the previous source word208t2 == the unshifted current source word. */209$u_eos:210extqh t2, a1, t0 # e0 :211or t0, t1, t0 # e1 : first (partial) source word complete212213cmpbge zero, t0, t8 # e0 : is the null in this first bit?214bne t8, $u_final # .. e1 (zdb)215216stq_u t0, 0(a0) # e0 : the null was in the high-order bits217addq a0, 8, a0 # .. e1 :218subq a2, 1, a2 # e1 :219220$u_late_head_exit:221extql t2, a1, t0 # .. e0 :222cmpbge zero, t0, t8 # e0 :223or t8, t10, t6 # e1 :224cmoveq a2, t6, t8 # e0 :225nop # .. e1 :226227/* Take care of a final (probably partial) result word.228On entry to this basic block:229t0 == assembled source word230t8 == cmpbge mask that found the null. */231$u_final:232negq t8, t6 # e0 : isolate low bit set233and t6, t8, t12 # e1 :234235and t12, 0x80, t6 # e0 : avoid dest word load if we can236bne t6, 1f # .. e1 (zdb)237238ldq_u t1, 0(a0) # e0 :239subq t12, 1, t6 # .. e1 :240or t6, t12, t8 # e0 :241zapnot t0, t8, t0 # .. e1 : kill source bytes > null242zap t1, t8, t1 # e0 : kill dest bytes <= null243or t0, t1, t0 # e1 :2442451: stq_u t0, 0(a0) # e0 :246br $finish_up247248$u_eoc: # end-of-count249extqh t2, a1, t0250or t0, t1, t0251cmpbge zero, t0, t8252253$u_eocfin: # end-of-count, final word254or t10, t8, t8255br $u_final256257/* Unaligned copy entry point. */258.align 3259$unaligned:260261EX( ldq_u t1, 0(a1) ) # e0 : load first source word262263and a0, 7, t4 # .. e1 : find dest misalignment264and a1, 7, t5 # e0 : find src misalignment265266/* Conditionally load the first destination word and a bytemask267with 0xff indicating that the destination byte is sacrosanct. */268269mov zero, t0 # .. e1 :270mov zero, t6 # e0 :271beq t4, 1f # .. e1 :272ldq_u t0, 0(a0) # e0 :273lda t6, -1 # .. e1 :274mskql t6, a0, t6 # e0 :2751:276subq a1, t4, a1 # .. e1 : sub dest misalignment from src addr277278/* If source misalignment is larger than dest misalignment, we need279extra startup checks to avoid SEGV. */280281cmplt t4, t5, t12 # e1 :282extql t1, a1, t1 # .. e0 : shift src into place283lda t2, -1 # e0 : for creating masks later284beq t12, $u_head # e1 :285286mskqh t2, t5, t2 # e0 : begin src byte validity mask287cmpbge zero, t1, t8 # .. e1 : is there a zero?288extql t2, a1, t2 # e0 :289or t8, t10, t5 # .. e1 : test for end-of-count too290cmpbge zero, t2, t3 # e0 :291cmoveq a2, t5, t8 # .. e1 :292andnot t8, t3, t8 # e0 :293beq t8, $u_head # .. e1 (zdb)294295/* At this point we've found a zero in the first partial word of296the source. We need to isolate the valid source data and mask297it into the original destination data. (Incidentally, we know298that we'll need at least one byte of that original dest word.) */299300ldq_u t0, 0(a0) # e0 :301negq t8, t6 # .. e1 : build bitmask of bytes <= zero302mskqh t1, t4, t1 # e0 :303and t6, t8, t12 # .. e1 :304subq t12, 1, t6 # e0 :305or t6, t12, t8 # e1 :306307zapnot t2, t8, t2 # e0 : prepare source word; mirror changes308zapnot t1, t8, t1 # .. e1 : to source validity mask309310andnot t0, t2, t0 # e0 : zero place for source to reside311or t0, t1, t0 # e1 : and put it there312stq_u t0, 0(a0) # e0 :313314$finish_up:315zapnot t0, t12, t4 # was last byte written null?316cmovne t4, 1, t4317318and t12, 0xf0, t3 # binary search for the address of the319and t12, 0xcc, t2 # last byte written320and t12, 0xaa, t1321bic a0, 7, t0322cmovne t3, 4, t3323cmovne t2, 2, t2324cmovne t1, 1, t1325addq t0, t3, t0326addq t1, t2, t1327addq t0, t1, t0328addq t0, t4, t0 # add one if we filled the buffer329330subq t0, v0, v0 # find string length331ret332333$zerolength:334clr v0335$exception:336ret337338.end __strncpy_from_user339340341