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