#
#  IPL stage 0 boot loader for diag25 accessed devices.
#    Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
#    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
#               Holger Smolinski(smolinsk@de.ibm.com)
# 		Carsten Otte (cotte@de.ibm.com)

#
# An fba blocklist is 8 bytes in length and contains 3 entries:
#   offset 0 : block number (32 bit)
#   offset 4 : size of blocks (16 bit)
#   offset 6 : number of blocks (16 bit) - 1
#
#  startup for ipl at address 0
#  second stage boot loader is loaded to 0x2000 and starts at 0x2008

# The first 24 bytes are loaded by ipl to addresses 0-23 (a PSW and two CCWs).
# The 1st CCW is used to read IPL2 record with Stage2.
# The parameters point to the bootmap file on disk

	.org   0x0
	.long  0x00080000,0x80000218           # PSW :the first 24 byte are loaded by IPL 
        .long  0x06002000,0x20000000           # read IPL stage 1 
.Lzero:	.long  0x00000000,0x00000000           # Parameters for Stage1   
	
STAGE2_DESC = 0x218

#        .include "common.S"
	.fill  32,1,0
#
# Program execution of the second stage boot loader starts at 0x1008
#
        .globl _start
_start: stm    %r0,%r15,0x180           # store all registers (loadparm !)
        basr   %r13,0
0:      l      %r15,3f-0b(%r13)         # load end of stack address
        l      %r1,0xb8                 # load ipl device subchannel id
        stsch  .Lschib-0b(%r13)
	l      %r2,6+.Lschib-0b(%r13)   # load devno
	bas    %r14,_enable_device-0b(%r13)
	la     %r6,STAGE2_DESC
1:	clc    .Lzero(8),8(%r6)
	jnz    2f
	l      %r3,4f-0b(%r13)
	basr   %r14,%r3
2:	la     %r6,8(%r6)
	lm     %r2,%r3,0(%r6)		# get block with load descriptors
	l      %r4,6+.Lschib-0b(%r13)
	l      %r5,4f-0b(%r13)
        bas    %r14,_load_direct-0b(%r13)
	l      %r2,6+.Lschib-0b(%r13)   # load devno
	bas    %r14,_disable_device-0b(%r13)
	l      %r2,6+.Lschib-0b(%r13)   # load devno
	j      1b
3:      .long  0x10000-96
4:	.long  0x2008

# expand enable/disable routines
#	device_fn
#
# Enable I/O on the ipl device. 
#   %r2 : device subchannel id
#
_enable_device:
        basr   %r13,0                   # base register
0:	st     %r2,.Liob-0b(2,%r13)	# iob->dev_nr=schib.devno;
	mvi    36+.Liob-0b(%r13),64	# iob->end_block = 64;
	mvc    36+.Liob-0b(2,%r13),4+STAGE2_DESC # iob->block_size=blocksize;
	la     %r2,.Liob-0b(%r13)
	la     %r2,.Liob-0b(%r13)
	slr    %r3,%r3                  # MDISK INIT_IO = 0
        bas    %r14,_ssch-0b(%r13)	# issue the diagnose
        br     %r14

#
# Disable I/O on the ipl device.
#   %r2 : device subchannel id
#
_disable_device:
        basr   %r13,0                   # base register
0:	st     %r2,.Liob-0b(2,%r13)	# iob->dev_nr=schib.devno;
	mvi    36+.Liob-0b(%r13),64	# iob->end_block = 64;
	mvc    36+.Liob-0b(2,%r13),4+STAGE2_DESC # iob->block_size=blocksize;
	la     %r3,2			# MDISK TERM_IO = 2
        bas    %r14,_ssch-0b(%r13)	# issue the diagnose
        br     %r14
		
# parameter
#   %r2+%r3: blocklist descriptor
#   %r4    : device subchannel id
#   %r5    : load address
# returns
#   %r2    : updated load address
_load_direct:
        stm    %r6,%r15,24(%r15)
        basr   %r13,0                   # base register
.Lbase:	s      %r15,.Lc96-.Lbase(%r13)  # create stack frame
	st     %r2,6+.Liob-.Lbase(%r13) 
	sll    %r3,16
	srl    %r3,16
	lr     %r12,%r5                 # save load address
	lr     %r10,%r3
	n      %r10,.Lc65535-.Lbase(%r13)       # low word = number of blocks
	la     %r10,1(%r10)             # add 1 to number of blocks
	lr     %r9,%r3
	srl    %r9,16                   # high word = size of blocks
	lr     %r8,%r2                  # save block number
.Lblks: 
	st     %r0,28+.Liob-.Lbase(%r13)# iob->block_count = nrblocks
	lr     %r3,%r8
        alr    %r8,%r0                  # increase start block
	slr    %r10,%r0                 # reduce number of blocks left
	lr     %r1,%r0
	l      %r1,.Lprd-.Lbase(%r13)   # load address of ccw area
        b      .Llpst-.Lbase(%r13)
.Lloop:	la     %r1,16(%r1)              # update ccw pointer
.Llpst: st     %r3,4(%r1)               # bio->block_number = block + 1;
	st     %r12,12(%r1)             # bio->buffer = (bh->b_data + size);
	alr    %r12,%r9                 # add block size to load address
        la     %r3,1(%r3)               # increase block counter
	bct    %r0,.Lloop-.Lbase(%r13)

	lr     %r2,%r11                 # pass subchannel id
        bas    %r14,_ssch-.Lbase(%r13)  # read up to 128 blocks
.Lexit:	lr     %r2,%r12                 # return updated load address
        lm     %r6,%r15,120(%r15)
        br     %r14
.Lschib:.long  64,1,0
.Lc96:	.long  96
.Lc128:	.long  128
.Lc65535:
	.long  65535
.Lprd:	.long  0x4000
.Lplo:	.long  0x6000
        .align 8
# offset 2 in locate: block count, offset 4 in locate: block number
.Lskbio:.long  0x02000000,0x00000000    # read bio skeleton

# expand io subroutines from iplcommon.s
#	io_subroutines
#
# Start I/O
# issue the diag 250
#
# %r2 :	dia250 command
#
_ssch:
        basr   %r13,0                   # base register
0:	la     0,.Liob-0b(%r13)
	diag   0,%r2,0x250
	ipm    %r2
	srl    %r2,28
	or     %r2,1
	br     %r14		
	.align 8
.Liob:	.fill  64,1,0

#
# Wait for interrupt subroutine
#   %r2 : device subchannel id
#   %r3 : address of irb
#
_wait4de:
        basr   %r13,0                   # base register
0:	lr     %r1,%r2
        mvc    0x58(8),5f-0b(%r13)       # set ext new psw
1:	lpsw   4f-0b(%r4)
2:	clc    0x86(2),6f-0b(%r13)	# int code
        bne    1b-0b(%r4)               # unequal -> continue waiting
	cli    0x8b,0x00
	be     3f-0b(%r4)
        bas    %r14,_panik-0b(%r13)	# read up to 128 blocks
3:      br     %r14
        .align 8
6:	.word  0x2603
4:	.long  0x010a0000,0x80000000+1b
5:	.long  0x00080000,0x80000000+2b # io new psw

#
# Panik routine. Loads a disabled wait psw
#   %r2 : panik code
#
_panik:
	basr   %r1,0
0:	st     %r2,1f-0b+4(%r1)         # store code in address part of psw
	lpsw   1f-0b(%r1)
	.align 8
1:	.long  0x000a0000,0x00000000

# fill the rest of the 4k block with zeroes
        #.org   0x1000
