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