blob: 231cd89b54fce71b0cfc09202db7a70ca758dfaf [file] [log] [blame]
#
# linux_logo in ARM assembly language
# based on the code from ll_asm-0.41
#
# By Vince Weaver <vince _at_ deater.net>
#
# Modified to remove non-deterministic system calls
# And to avoid reading from /proc
.include "logo.include"
# 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 results returned by the sysinfo syscall
.equ S_TOTALRAM,16
# Sycscalls
.equ SYSCALL_EXIT, 1
.equ SYSCALL_WRITE, 4
#
.equ STDIN,0
.equ STDOUT,1
.equ STDERR,2
.globl _start
_start:
ldr r11,data_addr
ldr r12,bss_addr
#=========================
# PRINT LOGO
#=========================
# LZSS decompression algorithm implementation
# by Stephan Walter 2002, based on LZSS.C by Haruhiko Okumura 1989
# optimized some more by Vince Weaver
ldr r1,out_addr @ buffer we are printing to
mov r2,#(N-F) @ R
add r3,r11,#(logo-data_begin)
@ r3 points to logo data
ldr r8,logo_end_addr
@ r8 points to logo end
ldr r9,text_addr @ r9 points to text buf
decompression_loop:
ldrb r4,[r3],#+1 @ load a byte, increment pointer
mov r5,#0xff @ load top as a hackish 8-bit counter
orr r5,r4,r5,LSL #8 @ shift 0xff left by 8 and or in the byte we loaded
test_flags:
cmp r3,r8 @ have we reached the end?
bge done_logo @ if so, exit
lsrs r5,#1 @ shift bottom bit into carry flag
bcs discrete_char @ if set, we jump to discrete char
offset_length:
ldrb r0,[r3],#+1 @ load a byte, increment pointer
ldrb r4,[r3],#+1 @ load a byte, increment pointer
@ we can't load halfword as no unaligned loads on arm
orr r4,r0,r4,LSL #8 @ merge back into 16 bits
@ this has match_length and match_position
mov r7,r4 @ copy r4 to r7
@ no need to mask r7, as we do it
@ by default in output_loop
mov r0,#(THRESHOLD+1)
add r6,r0,r4,LSR #(P_BITS)
@ r6 = (r4 >> P_BITS) + THRESHOLD + 1
@ (=match_length)
output_loop:
ldr r0,pos_mask @ urgh, can't handle simple constants
and r7,r7,r0 @ mask it
ldrb r4,[r9,r7] @ load byte from text_buf[]
add r7,r7,#1 @ advance pointer in text_buf
store_byte:
strb r4,[r1],#+1 @ store a byte, increment pointer
strb r4,[r9,r2] @ store a byte to text_buf[r]
add r2,r2,#1 @ r++
mov r0,#(N)
sub r0,r0,#1 @ grrr no way to get this easier
and r2,r2,r0 @ mask r
subs r6,r6,#1 @ decement count
bne output_loop @ repeat until k>j
tst r5,#0xff00 @ are the top bits 0?
bne test_flags @ if not, re-load flags
b decompression_loop
discrete_char:
ldrb r4,[r3],#+1 @ load a byte, increment pointer
mov r6,#1 @ we set r6 to one so byte
@ will be output once
b store_byte @ and store it
# end of LZSS code
done_logo:
ldr r1,out_addr @ buffer we are printing to
bl write_stdout @ print the logo
#==========================
# PRINT VERSION
#==========================
first_line:
mov r0,#0
add r1,r11,#(uname_info-data_begin)
@ os-name from uname "Linux"
ldr r10,out_addr @ point r10 to out_buffer
bl strcat @ call strcat
add r1,r11,#(ver_string-data_begin) @ source is " Version "
bl strcat @ call strcat
add r1,r11,#((uname_info-data_begin)+U_RELEASE)
@ version from uname, ie "2.6.20"
bl strcat @ call strcat
add r1,r11,#(compiled_string-data_begin)
@ source is ", Compiled "
bl strcat @ call strcat
add r1,r11,#((uname_info-data_begin)+U_VERSION)
@ compiled date
bl strcat @ call strcat
mov r3,#0xa
strb r3,[r10],#+1 @ store a linefeed, increment pointer
strb r0,[r10],#+1 @ NUL terminate, increment pointer
bl center_and_print @ center and print
@===============================
@ Middle-Line
@===============================
middle_line:
@=========
@ Load /proc/cpuinfo into buffer
@=========
ldr r10,out_addr @ point r10 to out_buffer
@=============
@ Number of CPUs
@=============
number_of_cpus:
add r1,r11,#(one-data_begin)
# cheat. Who has an SMP arm?
bl strcat
@=========
@ MHz
@=========
print_mhz:
@ the arm system I have does not report MHz
@=========
@ Chip Name
@=========
chip_name:
mov r0,#'s'
mov r1,#'o'
mov r2,#'r'
mov r3,#' '
bl find_string
@ find 'sor\t: ' and grab up to ' '
add r1,r11,#(processor-data_begin)
@ print " Processor, "
bl strcat
@========
@ RAM
@========
ldr r3,[r11,#((sysinfo_buff-data_begin)+S_TOTALRAM)]
@ size in bytes of RAM
movs r3,r3,lsr #20 @ divide by 1024*1024 to get M
adc r3,r3,#0 @ round
mov r0,#1
bl num_to_ascii
add r1,r11,#(ram_comma-data_begin)
@ print 'M RAM, '
bl strcat @ call strcat
@========
@ Bogomips
@========
mov r0,#'I'
mov r1,#'P'
mov r2,#'S'
mov r3,#'\n'
bl find_string
add r1,r11,#(bogo_total-data_begin)
bl strcat @ print bogomips total
bl center_and_print @ center and print
#=================================
# Print Host Name
#=================================
last_line:
ldr r10,out_addr @ point r10 to out_buffer
add r1,r11,#((uname_info-data_begin)+U_NODENAME)
@ host name from uname()
bl strcat @ call strcat
bl center_and_print @ center and print
add r1,r11,#(default_colors-data_begin)
@ restore colors, print a few linefeeds
bl write_stdout
@================================
@ Exit
@================================
exit:
mov r0,#0 @ result is zero
mov r7,#SYSCALL_EXIT
swi 0x0 @ and exit
@=================================
@ FIND_STRING
@=================================
@ r0,r1,r2 = string to find
@ r3 = char to end at
@ r5 trashed
find_string:
ldr r7,disk_addr @ look in cpuinfo buffer
find_loop:
ldrb r5,[r7],#+1 @ load a byte, increment pointer
cmp r5,r0 @ compare against first byte
ldrb r5,[r7] @ load next byte
cmpeq r5,r1 @ if first byte matched, comp this one
ldrb r5,[r7,#+1] @ load next byte
cmpeq r5,r2 @ if first two matched, comp this one
beq find_colon @ if all 3 matched, we are found
cmp r5,#0 @ are we at EOF?
beq done @ if so, done
b find_loop
find_colon:
ldrb r5,[r7],#+1 @ load a byte, increment pointer
cmp r5,#':'
bne find_colon @ repeat till we find colon
add r7,r7,#1 @ skip the space
store_loop:
ldrb r5,[r7],#+1 @ load a byte, increment pointer
strb r5,[r10],#+1 @ store a byte, increment pointer
cmp r5,r3
bne store_loop
almost_done:
mov r0,#0
strb r0,[r10],#-1 @ replace last value with NUL
done:
bx r14 @ return
#================================
# strcat
#================================
# value to cat in r1
# output buffer in r10
# r3 trashed
strcat:
ldrb r3,[r1],#+1 @ load a byte, increment pointer
strb r3,[r10],#+1 @ store a byte, increment pointer
cmp r3,#0 @ is it zero?
bne strcat @ if not loop
sub r10,r10,#1 @ point to one less than null
bx r14 @ return
#==============================
# center_and_print
#==============================
# string to center in at output_buffer
center_and_print:
stmfd SP!,{LR} @ store return address on stack
add r1,r11,#(escape-data_begin)
@ we want to output ^[[
bl write_stdout
str_loop2:
ldr r2,out_addr @ point r2 to out_buffer
sub r2,r10,r2 @ get length by subtracting
rsb r2,r2,#81 @ reverse subtract! r2=81-r2
@ we use 81 to not count ending \n
bne done_center @ if result negative, don't center
lsrs r3,r2,#1 @ divide by 2
adc r3,r3,#0 @ round?
mov r0,#0 @ print to stdout
bl num_to_ascii @ print number of spaces
add r1,r11,#(C-data_begin)
@ we want to output C
bl write_stdout
done_center:
ldr r1,out_addr @ point r1 to out_buffer
ldmfd SP!,{LR} @ restore return address from stack
#================================
# WRITE_STDOUT
#================================
# r1 has string
# r0,r2,r3 trashed
write_stdout:
mov r2,#0 @ clear count
str_loop1:
add r2,r2,#1
ldrb r3,[r1,r2]
cmp r3,#0
bne str_loop1 @ repeat till zero
write_stdout_we_know_size:
mov r0,#STDOUT @ print to stdout
mov r7,#SYSCALL_WRITE
swi 0x0 @ run the syscall
bx r14 @ return
@#############################
@ num_to_ascii
@#############################
@ r3 = value to print
@ r0 = 0=stdout, 1=strcat
num_to_ascii:
stmfd SP!,{r10,LR} @ store return address on stack
add r10,r12,#((ascii_buffer-bss_begin))
add r10,r10,#10
@ point to end of our buffer
mov r4,#10 @ we'll be dividing by 10
div_by_10:
bl divide @ Q=r7,$0, R=r8,$1
add r8,r8,#0x30 @ convert to ascii
strb r8,[r10],#-1 @ store a byte, decrement pointer
adds r3,r7,#0 @ move Q in for next divide, update flags
bne div_by_10 @ if Q not zero, loop
write_out:
add r1,r10,#1 @ adjust pointer
ldmfd SP!,{r10,LR} @ restore return address from stack
cmp r0,#0
bne strcat @ if 1, strcat
b write_stdout @ else, fallthrough to stdout
@===================================================
@ Divide - because ARM has no hardware int divide
@ yes this is an awful algorithm, but simple
@ and uses few registers
@==================================================
@ r3=numerator r4=denominator
@ r7=quotient r8=remainder
@ r5=trashed
divide:
mov r7,#0 @ zero out quotient
divide_loop:
mul r5,r7,r4 @ multiply Q by denominator
add r7,r7,#1 @ increment quotient
cmp r5,r3 @ is it greater than numerator?
ble divide_loop @ if not, loop
sub r7,r7,#2 @ otherwise went too far, decrement
@ and done
mul r5,r7,r4 @ calculate remainder
sub r8,r3,r5 @ R=N-(Q*D)
bx r14 @ return
bss_addr: .word bss_begin
data_addr: .word data_begin
out_addr: .word out_buffer
disk_addr: .word disk_buffer
logo_end_addr: .word logo_end
pos_mask: .word ((POSITION_MASK<<8)+0xff)
text_addr: .word text_buf
#===========================================================================
# section .data
#===========================================================================
.data
data_begin:
ver_string: .ascii " Version \0"
compiled_string: .ascii ", Compiled \0"
processor: .ascii " Processor, \0"
ram_comma: .ascii "M RAM, \0"
bogo_total: .ascii " Bogomips Total\n\0"
default_colors: .ascii "\033[0m\n\n\0"
escape: .ascii "\033[\0"
C: .ascii "C\0"
one: .ascii "One \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 "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"
.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.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"
.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"
disk_buffer:
.ascii "Processor : Feroceon 88FR131 rev 1 (v5l)\n"
.ascii "BogoMIPS : 1192.75\n"
.ascii "Features : swp half thumb fastmult edsp \n"
.ascii "CPU implementer : 0x56\n"
.ascii "CPU architecture: 5TE\n"
.ascii "CPU variant : 0x2\n"
.ascii "CPU part : 0x131\n"
.ascii "CPU revision : 1\n"
.ascii "\n"
.ascii "Hardware : Marvell SheevaPlug Reference Board\n"
.ascii "Revision : 0000\n"
.ascii "Serial : 0000000000000000\n\0"
sysinfo_buff:
.long 0,0,0,0,512*1024*1024,0,0,0
.include "logo.lzss_new"
#============================================================================
# section .bss
#============================================================================
.bss
bss_begin:
.lcomm ascii_buffer,10
.lcomm text_buf, (N+F-1)
.lcomm out_buffer,16384