# # linux_logo in ppc assembly language # based on the code from ll_asm-0.36 # # By Vince Weaver # # Modified to remove non-deterministic system calls # And to avoid reading from /proc # # offsets into the results returned by the uname syscall .equ U_SYSNAME,0 .equ U_NODENAME,65 .equ U_RELEASE,65*2 .equ U_VERSION,(65*3) .equ U_MACHINE,(65*4) .equ U_DOMAINNAME,65*5 # offset into the SYSCALL_SYSINFO buffer .equ S_TOTALRAM,16 # Sycscalls .equ SYSCALL_EXIT, 1 #.equ SYSCALL_READ, 3 .equ SYSCALL_WRITE, 4 #.equ SYSCALL_OPEN, 5 #.equ SYSCALL_CLOSE, 6 #.equ SYSCALL_SYSINFO,116 #.equ SYSCALL_UNAME, 122 # .equ STDIN, 0 .equ STDOUT,1 .equ STDERR,2 .equ BSS_BEGIN,25 .equ DATA_BEGIN,26 .include "logo.include" .globl _start _start: #======================== # Initialization #======================== # eieio # coolest opcode of all time ;) # not needed, but I had to put it here # the hack loading BSS_BEGIN and DATA_BEGIN # saves one instruction on any future load from memory # as we can just do an addi rather than an lis;addi lis 25,bss_begin@ha addi 25,25,bss_begin@l lis 26,data_begin@ha addi 26,26,data_begin@l addi 14,BSS_BEGIN,(out_buffer-bss_begin) # the output buffer addi 21,BSS_BEGIN,(text_buf-bss_begin) mr 17,14 # store out-buffer for later #========================= # PRINT LOGO #========================= # LZSS decompression algorithm implementation # by Stephan Walter 2002, based on LZSS.C by Haruhiko Okumura 1989 # optimized some more by Vince Weaver li 8,(N-F) # grab "R" addi 9,DATA_BEGIN,(logo-data_begin)-1 # logo_pointer addi 12,DATA_BEGIN,(logo_end-data_begin)-1 # end of the logo mr 16,17 decompression_loop: lbzu 10,1(9) # load in a byte # auto-update mr 11,10 # copy to 11 ori 11,11,0xff00 # re-load top as a hackish # 8-bit counter test_flags: cmpw 0,12,9 # have we reached the end? ble done_logo # ! if so exit andi. 13,11,0x1 srawi 11,11,1 bne 0,discrete_char offset_length: lbzu 10,1(9) lbzu 24,1(9) slwi 24,24,8 or 24,24,10 mr 10,24 srawi 15,10,P_BITS addi 15,15,THRESHOLD+1 # cl = ax >> (P_BITS)+THRESH+1 # = match length output_loop: andi. 24,24,(POSITION_MASK<<8+0xff) # mask it lbzx 10,21,24 addi 24,24,1 store_byte: stbu 10,1(16) stbx 10,21,8 addi 8,8,1 andi. 8,8,(N-1) addic. 15,15,-1 bne 0,output_loop andi. 13,11,0xff00 bne test_flags b decompression_loop discrete_char: lbzu 10,1(9) li 15,1 b store_byte done_logo: addi 4,17,1 # restore (plus one because r17 is decremented) bl write_stdout # and print the logo #========================== # First Line #========================== #========================== # PRINT VERSION #========================== # li 0,SYSCALL_UNAME # uname syscall # addi 3,BSS_BEGIN,(uname_info-bss_begin) # uname struct # sc # do syscall addi 16,DATA_BEGIN,(uname_info-data_begin)+U_SYSNAME@l-1 # os-name from uname "Linux" bl strcat addi 16,DATA_BEGIN,(ver_string-data_begin)-1 # source is " Version " bl strcat addi 16,DATA_BEGIN,(uname_info-data_begin)+U_RELEASE@l-1 # version from uname "2.4.1" bl strcat addi 16,DATA_BEGIN,(compiled_string-data_begin)-1 # source is ", Compiled " bl strcat addi 16,DATA_BEGIN,(uname_info-data_begin)+U_VERSION-1 # compiled date bl strcat bl center_and_print # write it to screen #=============================== # Middle-Line #=============================== #========= # Load /proc/cpuinfo into buffer #========= # li 0,SYSCALL_OPEN # open() # addi 3,DATA_BEGIN,(cpuinfo-data_begin) # '/proc/cpuinfo' # li 4,0 # O_RDONLY # sc # syscall. fd in r0. # we should check that r0>=0 # mr 13,3 # save fd in r13 # li 0,SYSCALL_READ # read # addi 4,BSS_BEGIN,(disk_buffer-bss_begin) # li 5,4096 # 4096 is maximum size of proc file ;) # sc # mr 3,13 # restore fd # li 0,6 # close # sc #============= # Number of CPUs #============= mr 14,17 # point output to out_buf # Assume 1 CPU for now # my iBook's /proc/cpuinfo does not have a "processor" line ??? addi 16,DATA_BEGIN,(one-data_begin)-1 bl strcat #========= # MHz #========= lis 20,('l'<<8)+'o' # find 'lock ' and grab up to M addi 20,20,('c'<<8)+'k' li 23,'M' bl find_string addi 16,DATA_BEGIN,(megahertz-data_begin)-1 # print 'MHz ' bl strcat #========= # Chip Name #========= lis 20,('c'<<8)+'p' # find 'cpu\t: ' and grab up to \n addi 20,20,('u'<<8)+'\t' li 23,'\n' bl find_string addi 16,DATA_BEGIN,(comma-data_begin)-1 # print ', ' bl strcat #======== # RAM #======== # li 0,SYSCALL_SYSINFO # sysinfo() syscall # addi 3,BSS_BEGIN,(sysinfo_buff-bss_begin) # sysinfo_buffer # sc lwz 4,(sysinfo_buff+S_TOTALRAM-data_begin)(DATA_BEGIN) # load bytes of RAM into r4 srawi 4,4,20 # divide by 2^20 to get MB li 5,0 bl num_to_ascii addi 16,DATA_BEGIN,(ram_comma-data_begin)-1 # print 'M RAM, ' bl strcat #======== # Bogomips #======== lis 20,('m'<<8)+'i' # find 'mips' and grab up to \n addi 20,20,('p'<<8)+'s' li 23,'\n' bl find_string addi 16,DATA_BEGIN,(bogo_total-data_begin)-1 # print "Bogomips Total" bl strcat bl center_and_print # center it #================================= # Print Host Name #================================= mr 14,17 # restore out buffer addi 16,DATA_BEGIN,((uname_info-data_begin)+U_NODENAME)-1 # hostname bl strcat bl center_and_print #================================ # Exit #================================ exit: li 3,0 # 0 exit value li 0,SYSCALL_EXIT # put the exit syscall number in eax sc # and exit #================================= # FIND_STRING #================================= # r23 is char to end at # r20 is the 4-char ascii string to look for # r14 points at output buffer # r16,r21 find_string: addi 16,DATA_BEGIN,(disk_buffer-data_begin)-1 # look in cpuinfo buffer # -1 so we can use lbzu find_loop: lwzu 13,1(16) # load in 32 bits, incrementing 8bits cmpwi 13,0 # ! if null, we are done beq done cmpw 13,20 # compare with out 4 char string bne find_loop # ! if no match, keep looping # ! if we get this far, we matched li 21,':' find_colon: lbzu 13,1(16) # repeat till we find colon cmpwi 13,0 beq done cmpw 13,21 bne find_colon addi 16,16,1 # skip a char [should be space] store_loop: lbzu 13,1(16) cmpwi 13,0 beq done cmpw 13,23 # is it end string? beq almost_done # ! if so, finish stbu 13,1(14) # ! if not store and continue b store_loop almost_done: li 13,0 # replace last value with null stb 13,1(14) done: blr #================================ # strcat #================================ # r13 = "temp" # r16 = "source" # r14 = "destination" strcat: lbzu 13,1(16) # load a byte from [r16] stbu 13,1(14) # store a byte to [r14] cmpwi 13,0 # is it zero? bne strcat # ! if not loop subi 14,14,1 # point to one less than null blr # return #============================== # center_and_print #============================== # r14 is end of buffer # r17 is start of buffer # r29 = saved link register # r4-r10, r19-r22, r30 trashed center_and_print: mflr 29 # back up return address subf 5,17,14 # see how long the output # buffer is cmpwi 5,80 # see if we are >80 bgt done_center # ! if so, bail li 4,80 # 80 column screen subf 4,5,4 # subtract strlen srawi 23,4,1 # divide by two lis 4,escape@ha addi 4,4,escape@l bl write_stdout mr 4,23 li 5,1 # print to stdout bl num_to_ascii # print number lis 4,c@ha addi 4,4,c@l bl write_stdout done_center: addi 4,17,1 # move string to output+1 bl write_stdout # call write stdout lis 4,linefeed@ha addi 4,4,linefeed@l mtlr 29 # restore link register # and let write_stdout # return for us #================================ # WRITE_STDOUT #================================ # r4 has string # r0,r3,r4,r5,r6 trashed write_stdout: li 0,SYSCALL_WRITE # write syscall li 3,STDOUT # stdout li 5,0 # string length counter strlen_loop: lbzx 6,4,5 # get byte from (r4+r5) addi 5,5,1 # increment counter cmpi 0,6,0 # is it zero? bne strlen_loop # ! if not keep counting addi 5,5,-1 sc # syscall blr # return ############################## # Num to Ascii ############################## # num is in r4 # r5 =0 then strcat, otherwise stdout # r5-r10,r19,r20,r21,r22,r30 trashed num_to_ascii: mflr 30 # save the link register addi 16,BSS_BEGIN,(num_to_ascii_end-bss_begin) # the end of a backwards growing # 10 byte long buffer. li 20,10 # we will divide by 10 mr 19,4 # load in the value passed div_by_10: divw 21,19,20 # divide r19 by r20 put into r21 mullw 22,21,20 # find remainder. 1st q*dividend subf 22,22,19 # then subtract from original = R addi 22,22,0x30 # convert remainder to ascii stbu 22,-1(16) # Store to backwards buffer mr 19,21 # move Quotient as new dividend cmpwi 19,0 # was quotient zero? bne div_by_10 # ! if not keep dividing write_out: cmpwi 5,0 # ! if r5 is 0 then skip ahead bne stdout_num addi 16,16,-1 # point to the beginning bl strcat # and strcat it mtlr 30 # restore link register blr # return stdout_num: mr 4,16 # point to our buffer mtlr 30 # restore link register b write_stdout # stdout will return for us #=========================================================================== .data #=========================================================================== data_begin: .include "logo.lzss_new" ver_string: .ascii " Version \0" compiled_string: .ascii ", Compiled \0" megahertz: .ascii "MHz PPC \0" .equ space, ram_comma+6 .equ comma, ram_comma+5 linefeed: .ascii "\n\0" escape: .ascii "\033[\0" c: .ascii "C\0" ram_comma: .ascii "M RAM, \0" bogo_total: .ascii " Bogomips Total\0" default_colors: .ascii "\033[0m\n\n\0" cpuinfo: .ascii "/proc/cpuinfo\0" one: .ascii "One \0" disk_buffer: .ascii "processor : 0\n" .ascii "cpu : 745/755\n" .ascii "temperature : 22-24 C (uncalibrated)\n" .ascii "clock : 600.000000MHz\n" .ascii "revision : 51.17 (pvr 0008 3311)\n" .ascii "bogomips : 49.79\n" .ascii "timebase : 24960000\n" .ascii "platform : PowerMac\n" .ascii "model : PowerBook4,1\n" .ascii "machine : PowerBook4,1\n" .ascii "motherboard : PowerBook4,1 MacRISC2 MacRISC Power Macintosh\n" .ascii "detected as : 257 (iBook 2)\n" .ascii "pmac flags : 0000001b\n" .ascii "L2 cache : 256K unified\n" .ascii "pmac-generation : NewWorld\n\0" uname_info: .ascii "Linux\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" .ascii "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" .ascii "henparma\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" .ascii "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" .ascii "2.6.29\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" .ascii "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" .ascii "#1 Wed May 13 15:51:54 UTC 2009\0" .ascii "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" .ascii "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" .ascii "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" .ascii "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" .ascii "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" sysinfo_buff: .long 0,0,0,0,512*1024*1024,0,0,0 #============================================================================ #.bss #============================================================================ .lcomm bss_begin,0 .lcomm num_to_ascii_buff,10 .lcomm num_to_ascii_end,1 .lcomm text_buf, (N+F-1) # These buffers must follow each other .lcomm out_buffer,16384