# # arch/s390/boot/ipleckd.S # IPL record for 3380/3390 DASD # # S390 version # Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation # Author(s): Holger Smolinski # # # FIXME: should use the countarea to determine the blocksize # FIXME: should insert zeroes into memory when filling holes # FIXME: calculate blkpertrack from rdc data and blksize # change 09/20/00 removed obsolete store of ipldevice to textesegment # Usage of registers # r1: ipl subchannel ( general use, dont overload without save/restore !) # r10: # r13: base register index to 0x0000 # r14: callers address # r15: temporary save register (we have no stack!) # storage layout: #include .org 0 .psw: .long 0x00080000,0x80000000+_start .ccw1: .long 0x06000000,0x00001000 # Re-Read enough of bootsector to start .ccw2: .long 0x00000000,0x00000000 # read countarea of record 1 to s/w. .org 0x58 .Lextn: .long 0x000a0000,0x00000000+.Lextn .Lsvcn: .long 0x000a0000,0x00000000+.Lsvcn .Lprgn: .long 0x00080000,0x00000000+.Lecs .Lmcn: .long 0x000a0000,0x00000000+.Lmcn .Lion: .long 0x00080000,0x80000000+.Lionewaddr .org 0xe0 .Llstad:.long 0x00000000,0x00000000 # sectorno + ct of bootlist .org 0xf0 # Lets start now... _start: .globl _start l %r1,__LC_SUBCHANNEL_ID # get IPL-subchannel from lowcore st %r1,__LC_IPLDEV # keep it for reipl stsch .Lrdcdata oi .Lrdcdata+5,0x84 # enable ssch and multipath mode .Lecs: xi .Lrdcdata+27,0x01 # enable concurrent sense msch .Lrdcdata xi .Lprgn,6 # restore Wait and d/a bit in PCnew PSW l %r2,.Lparm mvc 0x0(8,%r2),.Lnull # set parmarea to null lctl %c6,%c6,.Lc6 # enable all interrupts .Lrdc: # read device characteristics la %r6,.Lrdcccw st %r6,.Lorb+8 # store cp-address to orb bras %r15,.Lssch # start I/O oi .Llodata+1,0x80 lh %r5,.Lcountarea+6 # init r5 from countarea stcm %r5,3,.Lrdccw+2 # and store into rd template *FIXME* stcm %r5,3,.Llodata+14 # and store into lodata *FIXME* .Lbootlist: l %r2,.Llstad l %r3,.Lblklst lhi %r4,1 bras %r14,.Lreadblks .Lloader: l %r10,.Lblklst # r10 is index to bootlist lhi %r5,4 # r5: skip 4 blocks = firstpage.... .Lkloop: clc .Lnull(8),0(%r10) # test blocklist jz .Lchkparm # end of list? l %r2,0(%r10) # get startblock to r2 slr %r4,%r4 # erase r4 icm %r4,1,7(%r10) # get blockcount slr %r3,%r3 # get address to r3 icm %r3,0xe,4(%r10) chi %r5,0 # still blocks to skip? jz .Ldoread # no: start reading cr %r5,%r4 # #skipblocks >= blockct? jm .L007 # no: skip the blocks one by one .L006: sr %r5,%r4 # decrease number of blocks to skip j .Lkcont # advance to next entry .L007: ahi %r2,1 # skip 1 block... bctr %r4,0 # update blockct ah %r3,.Lcountarea+6 # increment address bct %r5,.L007 # 4 blocks skipped? .Ldoread: ltr %r2,%r2 # test startblock jz .Lzeroes # startblocks is zero (hole) .Ldiskread: bras %r14,.Lreadblks j .Lkcont .Lzeroes: lr %r2,%r3 .L001: slr %r3,%r3 icm %r3,3,.Lcountarea+6 # get blocksize slr %r5,%r5 # no bytes to move .L008: mvcle %r2,%r4,0 # fill zeroes to storage jo .L008 # until block is filled brct %r4,.L001 # skip to next block .Lkcont: ahi %r10,8 j .Lkloop .Lchkparm: lm %r3,%r4,.Lstart # load .Lstart and .Lparm clc 0x0(4,%r4),.Lnull je .Lrunkern mvc 0x480(128,%r3),0(%r4) # move 1k-0x80 to parmarea mvc 0x500(256,%r3),0x80(%r4) mvc 0x600(256,%r3),0x180(%r4) mvc 0x700(256,%r3),0x280(%r4) .Lrunkern: # lhi %r2,17 # sll %r2,12 # st %r1,0xc6c(%r2) # store iplsubchannel to lowcore # st %r1,0xc6c # store iplsubchannel to lowcore br %r3 # This function does the start IO # r2: number of first block to read ( input by caller ) # r3: address to read data to ( input by caller ) # r4: number of blocks to read ( input by caller ) # r5: destroyed # r6: blocks per track ( input by caller ) # r7: number of heads # r8: # r9: # r10: # r11: temporary register # r12: local use for base address # r13: base address for module # r14: address of caller for subroutine # r15: temporary save register (since we have no stack) .Lreadblks: la %r12,.Ldeccw st %r12,8+.Lorb # store cpaddr to orb ahi %r12,0x10 # increment r12 to point to rdccw oi 1(%r12),0x40 # set CC in rd template # first setup the read CCWs lr %r15,%r4 # save number or blocks slr %r7,%r7 icm %r7,3,.Lrdcdata+14 # load heads to r7 lhi %r6,9 clc .Lrdcdata+3(2),.L9345 je .L011 lhi %r6,10 clc .Lrdcdata+3(2),.L3380 je .L011 lhi %r6,12 clc .Lrdcdata+3(2),.L3390 je .L011 bras %r14,.Ldisab .L011: # loop for nbl times .Lrdloop: mvc 0(8,%r12),.Lrdccw # copy template to this ccw st %r3,4(%r12) # store target address to this ccw bct %r4,.L005 # decrement no of blks still to do ni 1(%r12),0x3f # delete CC from last ccw lr %r4,%r15 # restore number of blocks # read CCWs are setup now stcm %r4,3,.Llodata+2 # store blockno to lodata clears r4 ar %r4,%r2 # r4 (clear): ebl = blk + nbl bctr %r4,0 # decrement r4 ( last blk touched srda %r2,32 # trk = blk / bpt, bot = blk % bpt dr %r2,%r6 # r3: trk, r2: bot ahi %r2,1 # bot++ ( we start counting at 1 ) stcm %r2,1,.Llodata+12 # store bot to lodata xr %r2,%r2 # cy = trk / heads, hd = trk % heads dr %r2,%r7 # r3: cy, r2: hd sll %r3,16 # combine to CCHH in r3 or %r3,%r2 st %r3,.Ldedata+8 # store cchh to dedata st %r3,.Llodata+4 # store cchh to lodata st %r3,.Llodata+8 # store cchh to lodata lr %r15,%r5 # save r5 srda %r4,32 # tr2 = ebl / bpt dr %r4,%r6 # r5: tr2, r4: bot2 xr %r4,%r4 # cy2 = tr2 / heads, hd2 = hd2 % heads dr %r4,%r7 # r5: cy2, r4: hd2 stcm %r5,3,.Ldedata+12 # store cy2,hd2 to dedata stcm %r4,3,.Ldedata+14 # store cy2,hd2 to dedata lr %r5,%r15 # restore r5 # CCWs are setup now, arent they? bras %r15,.Lssch # start I/O br %r14 # return to caller .L005: ah %r3,.Lcountarea+6 # add blocksize to target address ahi %r12,8 # add sizeof(ccw) to base address j .Lrdloop # end of function # This function does the start IO # r1: Subchannel number # r8: ORB address # r9: IRB address .Lssch: lhi %r13,10 # initialize retries .L012: ssch .Lorb # start I/O jz .Ltpi # ok? bras %r14,.Ldisab # error .Ltpi: lpsw .Lwaitpsw # load wait-PSW .Lionewaddr: c %r1,0xb8 # compare to ipl subhchannel jnz .Ltpi # not equal: loop clc 0xbc(4),.Lorb # cross check the intparm jnz .Ltpi # not equal: loop tsch .Lirb # get status tm .Lirb+9,0xff # channel status ? jz .L003 # CS == 0x00 bras %r14,.Ldisab # error .L003: tm .Lirb+8,0xf3 # DS different from CE/DE jz .L004 # ok ? bct %r13,.L012 # retries <= 5 ? bras %r14,.Ldisab # error .L004: tm .Lirb+8,0x04 # DE set? jz .Ltpi # DE not set, loop .Lsschend: br %r15 # return to caller # end of function # In case of error goto disabled wait with %r14 containing the caller .Ldisab: st %r14,.Ldisabpsw+4 lpsw .Ldisabpsw # FIXME pre-initialized data should be listed first # NULLed storage can be taken from anywhere ;) .Lblklst: .long 0x00002000 .align 8 .Ldisabpsw: .long 0x000a0000,0x00000000 .Lwaitpsw: .long 0x020a0000,0x00000000+.Ltpi .Lorb: .long 0x0049504c,0x0080ff00 # intparm is " IPL" .Lc6: .long 0xff000000 .Lstart: .long 0x00010000 # do not separate .Lstart and .Lparm .Lparm: .long 0x00008000 # they are loaded with a LM .L3390: .word 0x3390 .L9345: .word 0x9345 .L3380: .word 0x3380 .Lnull: .long 0x00000000,0x00000000 .align 4 .Lrdcdata: .long 0x00000000,0x00000000 .long 0x00000000,0x00000000 .long 0x00000000,0x00000000 .long 0x00000000,0x00000000 .long 0x00000000,0x00000000 .long 0x00000000,0x00000000 .long 0x00000000,0x00000000 .long 0x00000000,0x00000000 .Lirb: .long 0x00000000,0x00000000 .long 0x00000000,0x00000000 .long 0x00000000,0x00000000 .long 0x00000000,0x00000000 .long 0x00000000,0x00000000 .long 0x00000000,0x00000000 .long 0x00000000,0x00000000 .long 0x00000000,0x00000000 .Lcountarea: .word 0x0000 # cyl; .word 0x0000 # head; .byte 0x00 # record; .byte 0x00 # key length; .word 0x0000 # data length == blocksize; .Ldedata: .long 0x40c00000,0x00000000 .long 0x00000000,0x00000000 .Llodata: .long 0x06000001,0x00000000 .long 0x00000000,0x01000000 .long 0x12345678 .org 0x7c8 .Lrdcccw: # CCW read device characteristics .long 0x64400040,0x00000000+.Lrdcdata .long 0x63400010,0x00000000+.Ldedata .long 0x47400010,0x00000000+.Llodata .long 0x12000008,0x00000000+.Lcountarea .Ldeccw: .long 0x63400010,0x00000000+.Ldedata .Lloccw: .long 0x47400010,0x00000000+.Llodata .Lrdccw: .long 0x86400000,0x00000000 .org 0x800 # end of pre initialized data is here CCWarea follows # from here we load 1k blocklist # end of function