1# 2# linux_logo in ARM assembly language 3# based on the code from ll_asm-0.41 4# 5# By Vince Weaver <vince _at_ deater.net> 6# 7# Modified to remove non-deterministic system calls 8# And to avoid reading from /proc 9 10.include "logo.include" 11 12# offsets into the results returned by the uname syscall 13.equ U_SYSNAME,0 14.equ U_NODENAME,65 15.equ U_RELEASE,65*2 16.equ U_VERSION,(65*3) 17.equ U_MACHINE,(65*4) 18.equ U_DOMAINNAME,65*5 19 20# offset into the results returned by the sysinfo syscall 21.equ S_TOTALRAM,16 22 23# Sycscalls 24.equ SYSCALL_EXIT, 1 25.equ SYSCALL_WRITE, 4 26 27# 28.equ STDIN,0 29.equ STDOUT,1 30.equ STDERR,2 31 32 .globl _start 33_start: 34 ldr r11,data_addr 35 ldr r12,bss_addr 36 37 #========================= 38 # PRINT LOGO 39 #========================= 40 41# LZSS decompression algorithm implementation 42# by Stephan Walter 2002, based on LZSS.C by Haruhiko Okumura 1989 43# optimized some more by Vince Weaver 44 45 ldr r1,out_addr @ buffer we are printing to 46 47 mov r2,#(N-F) @ R 48 49 add r3,r11,#(logo-data_begin) 50 @ r3 points to logo data 51 ldr r8,logo_end_addr 52 @ r8 points to logo end 53 ldr r9,text_addr @ r9 points to text buf 54 55decompression_loop: 56 ldrb r4,[r3],#+1 @ load a byte, increment pointer 57 58 mov r5,#0xff @ load top as a hackish 8-bit counter 59 orr r5,r4,r5,LSL #8 @ shift 0xff left by 8 and or in the byte we loaded 60 61test_flags: 62 cmp r3,r8 @ have we reached the end? 63 bge done_logo @ if so, exit 64 65 lsrs r5,#1 @ shift bottom bit into carry flag 66 bcs discrete_char @ if set, we jump to discrete char 67 68offset_length: 69 ldrb r0,[r3],#+1 @ load a byte, increment pointer 70 ldrb r4,[r3],#+1 @ load a byte, increment pointer 71 @ we can't load halfword as no unaligned loads on arm 72 73 orr r4,r0,r4,LSL #8 @ merge back into 16 bits 74 @ this has match_length and match_position 75 76 mov r7,r4 @ copy r4 to r7 77 @ no need to mask r7, as we do it 78 @ by default in output_loop 79 80 mov r0,#(THRESHOLD+1) 81 add r6,r0,r4,LSR #(P_BITS) 82 @ r6 = (r4 >> P_BITS) + THRESHOLD + 1 83 @ (=match_length) 84 85output_loop: 86 ldr r0,pos_mask @ urgh, can't handle simple constants 87 and r7,r7,r0 @ mask it 88 ldrb r4,[r9,r7] @ load byte from text_buf[] 89 add r7,r7,#1 @ advance pointer in text_buf 90 91store_byte: 92 strb r4,[r1],#+1 @ store a byte, increment pointer 93 strb r4,[r9,r2] @ store a byte to text_buf[r] 94 add r2,r2,#1 @ r++ 95 mov r0,#(N) 96 sub r0,r0,#1 @ grrr no way to get this easier 97 and r2,r2,r0 @ mask r 98 99 subs r6,r6,#1 @ decement count 100 bne output_loop @ repeat until k>j 101 102 tst r5,#0xff00 @ are the top bits 0? 103 bne test_flags @ if not, re-load flags 104 105 b decompression_loop 106 107discrete_char: 108 ldrb r4,[r3],#+1 @ load a byte, increment pointer 109 mov r6,#1 @ we set r6 to one so byte 110 @ will be output once 111 112 b store_byte @ and store it 113 114 115# end of LZSS code 116 117done_logo: 118 ldr r1,out_addr @ buffer we are printing to 119 120 bl write_stdout @ print the logo 121 122 #========================== 123 # PRINT VERSION 124 #========================== 125first_line: 126 127 mov r0,#0 128 add r1,r11,#(uname_info-data_begin) 129 @ os-name from uname "Linux" 130 131 ldr r10,out_addr @ point r10 to out_buffer 132 133 bl strcat @ call strcat 134 135 136 add r1,r11,#(ver_string-data_begin) @ source is " Version " 137 bl strcat @ call strcat 138 139 add r1,r11,#((uname_info-data_begin)+U_RELEASE) 140 @ version from uname, ie "2.6.20" 141 bl strcat @ call strcat 142 143 add r1,r11,#(compiled_string-data_begin) 144 @ source is ", Compiled " 145 bl strcat @ call strcat 146 147 add r1,r11,#((uname_info-data_begin)+U_VERSION) 148 @ compiled date 149 bl strcat @ call strcat 150 151 mov r3,#0xa 152 strb r3,[r10],#+1 @ store a linefeed, increment pointer 153 strb r0,[r10],#+1 @ NUL terminate, increment pointer 154 155 bl center_and_print @ center and print 156 157 @=============================== 158 @ Middle-Line 159 @=============================== 160middle_line: 161 @========= 162 @ Load /proc/cpuinfo into buffer 163 @========= 164 165 ldr r10,out_addr @ point r10 to out_buffer 166 167 @============= 168 @ Number of CPUs 169 @============= 170number_of_cpus: 171 172 add r1,r11,#(one-data_begin) 173 # cheat. Who has an SMP arm? 174 bl strcat 175 176 @========= 177 @ MHz 178 @========= 179print_mhz: 180 181 @ the arm system I have does not report MHz 182 183 @========= 184 @ Chip Name 185 @========= 186chip_name: 187 mov r0,#'s' 188 mov r1,#'o' 189 mov r2,#'r' 190 mov r3,#' ' 191 bl find_string 192 @ find 'sor\t: ' and grab up to ' ' 193 194 add r1,r11,#(processor-data_begin) 195 @ print " Processor, " 196 bl strcat 197 198 @======== 199 @ RAM 200 @======== 201 202 203 ldr r3,[r11,#((sysinfo_buff-data_begin)+S_TOTALRAM)] 204 @ size in bytes of RAM 205 movs r3,r3,lsr #20 @ divide by 1024*1024 to get M 206 adc r3,r3,#0 @ round 207 208 mov r0,#1 209 bl num_to_ascii 210 211 add r1,r11,#(ram_comma-data_begin) 212 @ print 'M RAM, ' 213 bl strcat @ call strcat 214 215 216 @======== 217 @ Bogomips 218 @======== 219 220 mov r0,#'I' 221 mov r1,#'P' 222 mov r2,#'S' 223 mov r3,#'\n' 224 bl find_string 225 226 add r1,r11,#(bogo_total-data_begin) 227 bl strcat @ print bogomips total 228 229 bl center_and_print @ center and print 230 231 #================================= 232 # Print Host Name 233 #================================= 234last_line: 235 ldr r10,out_addr @ point r10 to out_buffer 236 237 add r1,r11,#((uname_info-data_begin)+U_NODENAME) 238 @ host name from uname() 239 bl strcat @ call strcat 240 241 bl center_and_print @ center and print 242 243 add r1,r11,#(default_colors-data_begin) 244 @ restore colors, print a few linefeeds 245 bl write_stdout 246 247 248 @================================ 249 @ Exit 250 @================================ 251exit: 252 mov r0,#0 @ result is zero 253 mov r7,#SYSCALL_EXIT 254 swi 0x0 @ and exit 255 256 257 @================================= 258 @ FIND_STRING 259 @================================= 260 @ r0,r1,r2 = string to find 261 @ r3 = char to end at 262 @ r5 trashed 263find_string: 264 ldr r7,disk_addr @ look in cpuinfo buffer 265find_loop: 266 ldrb r5,[r7],#+1 @ load a byte, increment pointer 267 cmp r5,r0 @ compare against first byte 268 ldrb r5,[r7] @ load next byte 269 cmpeq r5,r1 @ if first byte matched, comp this one 270 ldrb r5,[r7,#+1] @ load next byte 271 cmpeq r5,r2 @ if first two matched, comp this one 272 beq find_colon @ if all 3 matched, we are found 273 274 cmp r5,#0 @ are we at EOF? 275 beq done @ if so, done 276 277 b find_loop 278 279find_colon: 280 ldrb r5,[r7],#+1 @ load a byte, increment pointer 281 cmp r5,#':' 282 bne find_colon @ repeat till we find colon 283 284 add r7,r7,#1 @ skip the space 285 286store_loop: 287 ldrb r5,[r7],#+1 @ load a byte, increment pointer 288 strb r5,[r10],#+1 @ store a byte, increment pointer 289 cmp r5,r3 290 bne store_loop 291 292almost_done: 293 mov r0,#0 294 strb r0,[r10],#-1 @ replace last value with NUL 295 296done: 297 bx r14 @ return 298 299 #================================ 300 # strcat 301 #================================ 302 # value to cat in r1 303 # output buffer in r10 304 # r3 trashed 305strcat: 306 ldrb r3,[r1],#+1 @ load a byte, increment pointer 307 strb r3,[r10],#+1 @ store a byte, increment pointer 308 cmp r3,#0 @ is it zero? 309 bne strcat @ if not loop 310 sub r10,r10,#1 @ point to one less than null 311 bx r14 @ return 312 313 314 #============================== 315 # center_and_print 316 #============================== 317 # string to center in at output_buffer 318 319center_and_print: 320 321 stmfd SP!,{LR} @ store return address on stack 322 323 add r1,r11,#(escape-data_begin) 324 @ we want to output ^[[ 325 bl write_stdout 326 327str_loop2: 328 ldr r2,out_addr @ point r2 to out_buffer 329 sub r2,r10,r2 @ get length by subtracting 330 331 rsb r2,r2,#81 @ reverse subtract! r2=81-r2 332 @ we use 81 to not count ending \n 333 334 bne done_center @ if result negative, don't center 335 336 lsrs r3,r2,#1 @ divide by 2 337 adc r3,r3,#0 @ round? 338 339 mov r0,#0 @ print to stdout 340 bl num_to_ascii @ print number of spaces 341 342 add r1,r11,#(C-data_begin) 343 @ we want to output C 344 bl write_stdout 345 346done_center: 347 ldr r1,out_addr @ point r1 to out_buffer 348 ldmfd SP!,{LR} @ restore return address from stack 349 350 #================================ 351 # WRITE_STDOUT 352 #================================ 353 # r1 has string 354 # r0,r2,r3 trashed 355write_stdout: 356 mov r2,#0 @ clear count 357 358str_loop1: 359 add r2,r2,#1 360 ldrb r3,[r1,r2] 361 cmp r3,#0 362 bne str_loop1 @ repeat till zero 363 364write_stdout_we_know_size: 365 mov r0,#STDOUT @ print to stdout 366 mov r7,#SYSCALL_WRITE 367 swi 0x0 @ run the syscall 368 bx r14 @ return 369 370 371 @############################# 372 @ num_to_ascii 373 @############################# 374 @ r3 = value to print 375 @ r0 = 0=stdout, 1=strcat 376 377num_to_ascii: 378 stmfd SP!,{r10,LR} @ store return address on stack 379 add r10,r12,#((ascii_buffer-bss_begin)) 380 add r10,r10,#10 381 @ point to end of our buffer 382 383 mov r4,#10 @ we'll be dividing by 10 384div_by_10: 385 bl divide @ Q=r7,$0, R=r8,$1 386 add r8,r8,#0x30 @ convert to ascii 387 strb r8,[r10],#-1 @ store a byte, decrement pointer 388 adds r3,r7,#0 @ move Q in for next divide, update flags 389 bne div_by_10 @ if Q not zero, loop 390 391write_out: 392 add r1,r10,#1 @ adjust pointer 393 ldmfd SP!,{r10,LR} @ restore return address from stack 394 395 cmp r0,#0 396 bne strcat @ if 1, strcat 397 398 b write_stdout @ else, fallthrough to stdout 399 400 401 @=================================================== 402 @ Divide - because ARM has no hardware int divide 403 @ yes this is an awful algorithm, but simple 404 @ and uses few registers 405 @================================================== 406 @ r3=numerator r4=denominator 407 @ r7=quotient r8=remainder 408 @ r5=trashed 409divide: 410 411 mov r7,#0 @ zero out quotient 412divide_loop: 413 mul r5,r7,r4 @ multiply Q by denominator 414 add r7,r7,#1 @ increment quotient 415 cmp r5,r3 @ is it greater than numerator? 416 ble divide_loop @ if not, loop 417 sub r7,r7,#2 @ otherwise went too far, decrement 418 @ and done 419 420 mul r5,r7,r4 @ calculate remainder 421 sub r8,r3,r5 @ R=N-(Q*D) 422 bx r14 @ return 423 424 425bss_addr: .word bss_begin 426data_addr: .word data_begin 427out_addr: .word out_buffer 428disk_addr: .word disk_buffer 429logo_end_addr: .word logo_end 430pos_mask: .word ((POSITION_MASK<<8)+0xff) 431text_addr: .word text_buf 432 433#=========================================================================== 434# section .data 435#=========================================================================== 436.data 437data_begin: 438ver_string: .ascii " Version \0" 439compiled_string: .ascii ", Compiled \0" 440processor: .ascii " Processor, \0" 441ram_comma: .ascii "M RAM, \0" 442bogo_total: .ascii " Bogomips Total\n\0" 443 444default_colors: .ascii "\033[0m\n\n\0" 445escape: .ascii "\033[\0" 446C: .ascii "C\0" 447 448one: .ascii "One \0" 449 450uname_info: 451.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" 452.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" 453.ascii "lindt\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" 454.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" 455.ascii "2.6.32\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" 456.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" 457.ascii "#1 Wed May 13 15:51:54 UTC 2009\0" 458.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" 459.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" 460.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" 461.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" 462.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" 463 464 465disk_buffer: 466.ascii "Processor : Feroceon 88FR131 rev 1 (v5l)\n" 467.ascii "BogoMIPS : 1192.75\n" 468.ascii "Features : swp half thumb fastmult edsp \n" 469.ascii "CPU implementer : 0x56\n" 470.ascii "CPU architecture: 5TE\n" 471.ascii "CPU variant : 0x2\n" 472.ascii "CPU part : 0x131\n" 473.ascii "CPU revision : 1\n" 474.ascii "\n" 475.ascii "Hardware : Marvell SheevaPlug Reference Board\n" 476.ascii "Revision : 0000\n" 477.ascii "Serial : 0000000000000000\n\0" 478 479 480sysinfo_buff: 481.long 0,0,0,0,512*1024*1024,0,0,0 482 483.include "logo.lzss_new" 484 485 486#============================================================================ 487# section .bss 488#============================================================================ 489.bss 490bss_begin: 491.lcomm ascii_buffer,10 492.lcomm text_buf, (N+F-1) 493.lcomm out_buffer,16384 494