-
Notifications
You must be signed in to change notification settings - Fork 11
/
mt86+_loader.asm
231 lines (189 loc) · 6.26 KB
/
mt86+_loader.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
; A loader for www.memtest.org images, by Eric Auer 2003.
; This assumes that the image starts with the boot sector,
; which has the size of setup.S in sectors in a byte at offset
; 1f1h (497). Further, I assume setup.S directly after the boot
; sector and the actual memtest head.S after setup.S ...
; This version is derived from memtestL loader, which loads
; memtest.bin from a separate file. This version is meant to
; be used like (DOS / Unix variants):
; copy /b memteste.bin + memtest.bin memtest.exe
; cat memteste.bin memtest.bin > memtest.exe
; The good thing is that you get a single file which can be
; compressed, for example with http://upx.sf.net/ (UPX).
%define fullsize (164504 + buffer - exeh)
; 164504 is the size of memtest86+ V4.20, adjust as needed!
%define stacksize 2048
%define stackpara ((stacksize + 15) / 16)
; the trick is that NASM believes the header would be part
; of the loaded image, so we "org 20h bytes too early" to fix:
org 0e0h ; NASM thinks after header we have 100h
; which is what we want it to think.
exeh: db "MZ"
dw fullsize % 512 ; how much to load from
dw (fullsize + 511) / 512 ; .exe to RAM
dw 0 ; no relocations used
dw 2 ; header size is 2 * 16 bytes
dw stackpara ; minimum heap is 128 * 16 bytes, for stack
dw stackpara ; we do not need more heap either
dw (fullsize + 15) / 16 ; SS is after file
; segment offsets are relative to PSPseg+10h
; initial DS and ES point to PSPseg, and file
; except headers is loaded to PSPseg+10h.
dw stacksize-4 ; initial SP value
dw 0 ; no checksum
dw 100h ; initial IP
dw -10h ; initial CS relative to PSPseg+10h
dw 0 ; no relocation table, "offset 0 in file"
dw 0 ; this is not an overlay
db "MEMT" ; padding to a multiple of 16 bytes
; loaded part begins here (set CS so that IP is 100h here)
start: ; entry point ; if you use obj + linker, use "..start:"
mov ah, 01h
mov bh, 00h
mov cx, 2000h
int 10h
mov ax,cs ; ***
mov ds,ax ; ***
mov es,ax ; ***
; test if we have 386 or better:
pushf ; save flags
xor ax,ax
push ax
popf ; try to clear all bits
pushf
pop ax
and ax,0f000h
cmp ax,0f000h
jz noinst1 ; 4 msb stuck to 1: 808x or 80186
mov ax,0f000h
push ax
popf ; try to set 4 msb
pushf
pop ax
test ax,0f000h
jz noinst1 ; 4 msb stuck to 0: 80286
popf ; restore flags
jmp short found386
noinst1:
popf ; restore flags
mov dx,need386
jmp generror
found386: ; now test if the system is in real mode:
smsw ax ; MSW is the low half of CR0
; (smsw is not priv'd, unlike mov eax,cr0)
test al,1 ; if the PE (protected mode) flag on?
%ifndef DEBUG ; ignore findings in debug mode
jnz foundprotected
%endif
jmp foundreal
foundprotected:
mov dx,noreal
jmp generror
; ------------
need386 db "Sorry, you need at least a 386 CPU to use Memtest86+."
db 13,10,"$"
noreal db "You cannot run Memtest86+ if the system already is in"
db " protected mode.",13,10,"$"
; ------------
generror: ; generic error exit
push cs
pop ds
push cs
pop es
mov ah,9
int 21h
mov ax,4c01h
int 21h
; ------------
foundreal:
mov cx,buffer+15
shr cx,4 ; buffer offset in paragraphs
mov ax,cs
add ax,cx ; buffer offset in paragraphs
; now AX is the buffer segment
mov [cs:bufsetup+2],ax ; far pointer to boot sector now
mov cx,20h ; size of boot sector in paragraphs
add [cs:bufsetup+2],cx ; far pointer to setup now
movzx eax,ax
shl eax,4 ; linear buffer offset
mov [cs:buflinear],eax
findpoint: ; now patch the loader!
mov al,[buffer+1f1h] ; size of setup.S in sectors
; should be 4 ...
inc al ; the boot sector itself
movzx eax,al
shl eax,9 ; log 2 of sector size
add [cs:buflinear],eax ; linear address of head.S now
mov ax,[buffer+251h] ; should be jmp far dword (ofs, seg)
cmp ax,0ea66h
jz foundpatch
patchbug: ; could not patch the jump
mov dx,nopatch
jmp generror
gdtbug:
mov dx,nogdt
jmp generror
foundpatch:
mov eax,[cs:buflinear]
mov [buffer+253h],eax ; patch the protected mode entry jump
; (offset only - segment selector unchanged: flat linear CS)
findgdt:
mov eax,[cs:buffer+20ch] ; should be lgdt offset
and eax,00ffffffh
cmp eax,0016010fh ; lgdt ...
jnz gdtbug
mov ax,[cs:buffer+20fh] ; GDTR contents pointer
mov bx,ax
mov eax,[cs:buffer+200h+bx+2] ; GDT linear offset
and eax,1ffh ; assume GDT in first sector of setup.S
; *** WARNING: this is needed because setup.S contains
; *** HARDCODED offset of setup.S on linear 90200h, which
; *** is 90000h + bootsect.S ... flaw in Memtest86!
mov cx,[cs:bufsetup+2] ; setup.S segment
movzx ecx,cx
shl ecx,4 ; linear setup.S address
add eax,ecx ; fixed GDT linear offset
mov [cs:buffer+200h+bx+2],eax ; patch it
;mov dx,trying
;mov ah,9
;int 21h
;xor ax,ax
;int 16h ; wait for a keypress from the user
mov ax,[cs:bufsetup+2] ; setup segment
mov ds,ax ; set nice data segments for setup.S ...
mov es,ax
xor ax,ax
mov fs,ax
mov gs,ax
cli
lss sp,[cs:newstack] ; stack in first 64k now!
movzx esp,sp ; ensure 16bit stack pointer
; Memtest86 head.S assumes that it can just turn SS to
; linear. This would put the stack at 0:200h or so for us
; if we fail to move the stack around ...
%ifdef DEBUG
mov ebp,[cs:buflinear] ; will show up in debugging logs
mov esi,[cs:bufsetup] ; will show up in debugging logs
%endif
jmp far [cs:bufsetup]
; setup.S will enable the A20 (ignoring HIMEM, just using
; the classic 8042 programming trick) and turn on protected
; mode. Then it will jump to head.S, which luckily can run
; from any offset inside the linear 4 GB CS ...
; ------------
buflinear dd 0 ; linear address of head.S entry point
bufsetup dw 0,0 ; far pointer to setup.S entry point
newstack dw 03fch,0 ; beware, stack will overwrite IDT.
; ------------
nopatch db "jmp far dword not found at setup.S offset 37h,",13,10
db "(file offset 237h is not 66h, 0eah)",13,10
db "please adjust and recompile memtestl...",13,10,"$"
nogdt db "lgdt [...] not found at setup.S offset 0ch,",13,10
db "(file offset 20ch is not 0fh, 01h, 16h)",13,10
db "please adjust and recompile memtestl...",13,10,"$"
trying db "Now trying to start Memtest86...",13,10
db "You have to reboot to leave Memtest86 again.",13,10
db "Press a key to go on.",13,10,"$"
; ------------
align 16
buffer: ; a label pointing to where in the file memtest.bin will be.