1/*
2;  arm-linux.kernel.vmlinux.S -- loader & decompressor for the vmlinux/arm format
3;
4;  This file is part of the UPX executable compressor.
5;
6;  Copyright (C) 1996-2020 Markus Franz Xaver Johannes Oberhumer
7;  Copyright (C) 1996-2020 Laszlo Molnar
8;  Copyright (C) 2004-2020 John Reiser
9;  All Rights Reserved.
10;
11;  UPX and the UCL library are free software; you can redistribute them
12;  and/or modify them under the terms of the GNU General Public License as
13;  published by the Free Software Foundation; either version 2 of
14;  the License, or (at your option) any later version.
15;
16;  This program is distributed in the hope that it will be useful,
17;  but WITHOUT ANY WARRANTY; without even the implied warranty of
18;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19;  GNU General Public License for more details.
20;
21;  You should have received a copy of the GNU General Public License
22;  along with this program; see the file COPYING.
23;  If not, write to the Free Software Foundation, Inc.,
24;  59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25;
26;  Markus F.X.J. Oberhumer              Laszlo Molnar
27;  <markus@oberhumer.com>               <ezerotven+github@gmail.com>
28;
29;  John Reiser
30;  <jreiser@users.sourceforge.net>
31*/
32
33#include "arch/arm/v5a/macros.S"
34
35
36/*
37; =============
38; ============= ENTRY POINT
39; =============
40
41  How to debug: run under qemu (http://fabrice.bellard.free.fr/qemu/)
42  after un-commenting the  bkpt  opcode below.  That opcode forces qemu
43  to stop in gdb.  You'll have to "set $pc+=4" by hand.
44*/
45section         LINUX000
46        // bkpt  // qemu DEBUG only  // 'bkpt' == 0xe1200070
47/* Calling sequence of equivalent code in arch/arm/boot/compressed/misc.c:
48decompress_kernel:  # (char *out, char *tmp, char *tmp_end, int arch_id)
49        lr= &indata; ip= retaddr  # from arm-linux.kernel.vmlinux-head.S
50*/
51        str ip,[r2,#-4]!  // push retaddr on new stack
52        stmdb   r2!,{r0,r3,sp}  // &outdata, arch_id, sp_in
53        sub     r2,r2,#4  // space for outsize
54        loadcon8      3,METHOD  // mov r3,#METHOD
55        stmdb   r2!,{r3,lr}  // METHOD, &indata
56        mov sp, r2  // method,&indata,space,&outdata,arch_id,sp_in,retaddr
57
58        ldr r3,2f  // outsize
59        str r3,[sp,#2*4] //  outsize
60        add r3, sp,#2*4  // &outsize
61        mov r2,r0  // &outdata
62        ldr r1,1f  // insize
63        mov r0,lr  // &indata
64        bl decompressor  // (&indata, insize, &outdata, &outsize, method)
65        b 3f
661:
67        .long   COMPRESSED_LENGTH
682:
69        .long UNCOMPRESSED_LENGTH
703:
71spin:
72        cmp r0,#0  // check for success
73        bne spin
74
75section         LINUX010
76        ldr r0,[sp,#3*4]  // &outdata
77        ldr r1,[sp,#2*4]  // outsize
78        loadcon8 2,filter_cto   // mov r2,#filter_cto
79        loadcon8 3,filter_id    // mov r3,#filter_id
80        bl unfilter  // unfilter(&outdata, outsize, cto, fid)
81
82section         LINUX020
83        ldmia sp,{r0,r1,r2,r3,ip,sp,lr}  // method, &indata, outsize, &outdata, arch_id, sp_in, retaddr
84// See arch/arm/boot/compressed/misc.c/flush_window(): out = &output_data[output_ptr];
85        mov r0,r2  // rv= outsize
86        mov pc,lr  // return
87
88// =============
89// ============= UNFILTER
90// =============
91section         ctok32.00
92//f_unfilter:  @ (char *ptr, uint len, uint cto, uint fid)
93        ptr  .req r0
94        len  .req r1
95        cto  .req r2  @ unused
96        fid  .req r3
97
98        t1   .req r2
99        t2   .req r3
100unfilter:
101        and fid,fid,#0xff
102section         ctok32.50
103        cmp fid,#0x50  @ last use of fid
104section         ctok32.51
105        cmp fid,#0x51  @ last use of fid
106
107section         ctok32.10
108        movne pc,lr  @ no-op if not filter 0x50
109
110        movs  len,len,lsr #2  @ word count
111        cmpne ptr,#0
112        moveq pc,lr  @ no-op if either len or ptr is 0
113
114top_unf:
115        sub len,len,#1
116        ldr t1,[ptr,len,lsl #2]
117        and t2,t1,#0x0f<<24
118        cmp t2,   #0x0b<<24; bne tst_unf  @ not 'bl' subroutine call
119        and t2,t1,#0xff<<24  @ all the non-displacement bits
120        sub t1,t1,len  @ convert to word-relative displacement
121        bic t1,t1,#0xff<<24  @ restrict to displacement field
122        orr t1,t1,t2  @ re-combine
123        str t1,[ptr,len,lsl #2]
124tst_unf:
125        cmp len,#0
126        bne top_unf
127        mov pc,lr
128
129        .unreq ptr
130        .unreq len
131        .unreq cto
132        .unreq fid
133
134section         LINUX030
135decompressor:
136/*
137  r0= inptr
138  r1= insize
139  r2= outptr
140  r3= &outsize
141  sp/ method
142*/
143
144// =============
145// ============= DECOMPRESSION
146// =============
147
148section NRV2B
149#include "arch/arm/v5a/nrv2b_d8.S"
150
151section NRV2D
152#include "arch/arm/v5a/nrv2d_d8.S"
153
154section NRV2E
155#include "arch/arm/v5a/nrv2e_d8.S"
156
157#include "arch/arm/v5a/lzma_d.S"
158
159#include "include/header.S"
160
161/* vim:set ts=8 sw=8 et: */
162