File: mt86+_loader.asm

package info (click to toggle)
memtest86+ 5.01-3
  • links: PTS
  • area: main
  • in suites: buster, sid
  • size: 1,336 kB
  • ctags: 2,585
  • sloc: ansic: 17,514; asm: 1,805; makefile: 239; sh: 127
file content (231 lines) | stat: -rw-r--r-- 6,406 bytes parent folder | download | duplicates (3)
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
231
; 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 (150024 + buffer - exeh)
	; 150024 is the size of memtest86+ V5.01, 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.