source: trunk/BOOTCODE/SPECIAL/LINUX.ASM@ 38

Last change on this file since 38 was 38, checked in by Ben Rietbroek, 12 years ago

Converting to JWasm -- phase #1 (not working) [2012-02-15]

WARNING!!

All commits upto and including the commit of [2012-05-13] contain
a severe bug!! Building from these sources and then disabling
the 'force LBA' feature while also using the drive-letter feature or
editing the label can DESTROY THE MBR on ALL ATTACHED DISKS!!
DO NOT DISABLE 'FORCE LBA USAGE' WHEN BUILT FROM THE THESE COMMITS!!

Problems

o WLink generates an oversized image
o Only Tasm with TLink works correctly

File size: 17.5 KB
Line 
1; AiR-BOOT (c) Copyright 1998-2008 M. Kiewitz
2;
3; This file is part of AiR-BOOT
4;
5; AiR-BOOT is free software: you can redistribute it and/or modify it under
6; the terms of the GNU General Public License as published by the Free
7; Software Foundation, either version 3 of the License, or (at your option)
8; any later version.
9;
10; AiR-BOOT is distributed in the hope that it will be useful, but WITHOUT ANY
11; WARRANTY: without even the implied warranty of MERCHANTABILITY or FITNESS
12; FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13; details.
14;
15; You should have received a copy of the GNU General Public License along with
16; AiR-BOOT. If not, see <http://www.gnu.org/licenses/>.
17;
18;---------------------------------------------------------------------------
19; AiR-BOOT / LINUX SUPPORT
20;---------------------------------------------------------------------------
21
22; Here is the startup-code for Linux-Kernels. I'm sure this won't work on
23; all of them, but on the latest.
24
25; Note: This code will ONLY WORK on computers with INT 13h Extension.
26; I did not want to code silly cylinder stuff here and if you don't
27; have INT 13h Extensions, you will not need this. LINUXIMG won't work
28; without them.
29;
30; And another note: *F**k* Linux usenet-users. Really. I mean *f**k them*.
31; I asked in an OS/2 newsgroup for testers -> Got 8 volunteers within some
32; days. I asked in 2 Linux newsgroups. What did happen? Some idiots discussed
33; the whole sh*t with me, knew nothing about INT13h CHS/LBA mode, BIOS,
34; boot-managers in general, assembly coding and other stuff and wanted to tell
35; me that 95k GRUB is well-coded and its good to have it placed all over your
36; harddrive and that file-support and all those lousy features would waste
37; sooo much space. ROFLMAO.
38;
39; I could implement some more file-systems into AiR-BOOT, but instead I did
40; some nice menus, setup, text, cyrillic support, demo-coder effects, easy
41; handling, help, auto-detection and plenty of other stuff INTO AROUND 25k.
42;
43; Oh, why is this code here? Because of 2 friends of mine. Otherwise I wouldnt
44; have done it as well as fat16.asm.
45
46IFDEF ModuleNames
47DB 'LINUX',0
48ENDIF
49
50Linux_TranslateBase db '/dev/hd'
51Linux_KernelDirectory db 'KERNELS '
52
53; Translates partition-number to Linux-device name (e.g. /dev/hda3)
54; In: DL - partition number, ES:DI - destination 9-byte buffer
55; Out: (buffer filled)
56; Destroyed: None
57LINUX_TranslateToDEV Proc Near Uses eax ebx cx dx ds si
58 ; Damn Linux. Our logic is as follows: first get the drive letter.
59 ; that's easy. Now search our partition-table for new
60 ; extended partitions and fix them up. Stupid logic.
61 push cs
62 pop ds ; CS == DS
63 mov si, offset Linux_TranslateBase
64 mov cx, 7
65 rep movsb ; First write base-name (/dev/hd)...
66 ; First get our partition-table
67 call PART_GetPartitionPointer ; Partition (DL) -> CS:SI
68 mov dl, ds:[si+LocIPT_Drive]
69 mov al, dl
70 sub al, 1Fh ; Generate letter from drive (80h -> 61h)
71 stosb ; write letter
72
73 ; Now get the linux local partition number
74 ; 1. Search for partition, where TranslateDrive (DL) got used first
75 mov cx, si ; CX - Searched partition offset
76 mov si, offset PartitionTable ; begin here
77 LTTD_SearchDriveLoop:
78 cmp ds:[si+LocIPT_Drive], dl
79 je LTTD_SearchDrive_Found
80 add si, LocIPT_LenOfIPT
81 jmp LTTD_SearchDriveLoop
82 LTTD_SearchDrive_Found:
83 ; Now count all partitions to hit. After root partition set counter to
84 ; 4 and count further.
85 xor dh, dh ; Linux Partition Counter (Base 0)
86 LTTD_SearchPart_Loop:
87 inc dh ; Increase Linux Local Partition Number
88 mov ax, wptr ds:[si+LocIPT_AbsolutePartTable+2]
89 shr eax, 16
90 mov ax, wptr ds:[si+LocIPT_AbsolutePartTable+0] ; -> EAX
91 cmp dh, 4 ; over root partition yet ?
92 ja LTTD_ContinueLoop ; yes, continue loop
93 cmp eax, 0 ; not in root partition anymore?
94 je LTTD_ContinueLoop
95 mov dh, 5 ; nope, so adjust counter
96 LTTD_ContinueLoop:
97 cmp si, cx
98 je LTTD_SearchPart_Found
99 add si, LocIPT_LenOfIPT ; Next Partition
100 jmp LTTD_SearchPart_Loop
101
102 LTTD_SearchPart_Found:
103 or eax, eax
104 jnz LTTD_SearchPart_NotRootPartition
105 ; Bullshit, it's in the MBR, so we have to look for the
106 ; partition number directly (because EXTEND, EXT2: EXT2 would be
107 ; partition 1, in fact it would be partition 2)
108 ; All we do here is to load the MBR to memory (suck) and look in it
109 ; manually. Pervertly this could be crazy, when user
110 ; is in setup and changing 'Linux Root'.
111 mov ax, wptr ds:[si+LocIPT_AbsoluteBegin+2]
112 shr eax, 16
113 mov ax, wptr ds:[si+LocIPT_AbsoluteBegin+0] ; -> EAX
114 push eax
115 xor ax, ax
116 xor bx, bx
117 mov cx, 1
118 xor dh, dh
119 mov si, offset TmpSector
120 call DriveIO_LoadSector ; Load fucking MBR
121 pop eax
122 xor dh, dh ; Reset again to zero
123 add si, 446
124 LTTD_SearchRoot_Loop:
125 cmp bptr ds:[si+4], 0
126 je LTTD_SearchRoot_NoPart ; if partition...
127 inc dh ; add one
128 LTTD_SearchRoot_NoPart:
129 mov bx, wptr ds:[si+10]
130 shr ebx, 16
131 mov bx, wptr ds:[si+08] ; -> EBX (Start Sector)
132 add si, 16
133 cmp eax, ebx
134 jne LTTD_SearchRoot_Loop
135
136 LTTD_SearchPart_NotRootPartition:
137 mov al, dh
138 ; Now convert that crap (AL) to ascii and write it
139 cmp al, 10
140 jb LTTD_Smaller10
141 xor ah, ah
142 mov dl, 10
143 div dl
144 add al, 30h ; Generate number from value 00h -> 30h)
145 stosb
146 mov al, ah
147 LTTD_Smaller10:
148 add al, 30h ; Generate number from value
149 stosb
150 ret
151LINUX_TranslateToDEV EndP
152
153LINUX_InitFAT16access Proc Near Uses es
154 mov dl, ds:[CFG_LinuxKrnlPartition]
155 call PART_GetPartitionPointer ; Partition DL -> SI
156 call FAT16_InitAccess
157
158 call FAT16_ReadRoot
159
160 mov cx, FAT16_NumOfRootEntries
161 mov si, offset Linux_KernelDirectory
162 call FAT16_SearchEntry ; Fills up DX as Cluster-No
163 or dx, dx
164 jz LIFAT16A_NoDirectory
165
166 mov ax, 9000h
167 mov es, ax
168 xor di, di ; Read Cluster DX to 9000:0 (ES:DI)
169 call FAT16_ReadCluster
170 mov ax, cs
171 mov es, ax ; DS == ES == CS
172 call FAT16_ProcessKrnlDirectory
173
174 LIFAT16A_NoDirectory:
175 ret
176LINUX_InitFAT16access EndP
177
178; Initialize FAT-16 access on specified partition (required for following xs)
179; In: DS:SI - 11-Byte Kernel Name to search
180; Out: DL - FFh - if not found, otherwise the entry no is replied
181; Destroyed: None
182LINUX_SearchKernelName Proc Near Uses cx di
183 mov dl, 0FFh ; Nothing found is default...
184 mov cl, LINUX_KernelNo
185 or cl, cl
186 jz LSKN_NotFound
187 mov di, offset LINUX_KernelEntries
188 add di, LocIPT_Name
189 LSKN_SearchLoop:
190 push cx si di
191 mov cx, 11
192 repe cmpsb ; Compare total 11-bytes
193 pop di si cx
194 je LSKN_Found
195 add di, LocIPT_LenOfIPT
196 dec cl
197 jnz LSKN_SearchLoop
198 jmp LSKN_NotFound
199
200 LSKN_Found:
201 mov si, di
202 sub si, LocIPT_Name ; Back to Base-Pointer
203 call PART_GetPartitionNumber ; Get Number of Entry at [SI]
204 LSKN_NotFound:
205 ret
206LINUX_SearchKernelName EndP
207
208Linux_FuzzyString db 'Linux Boot - Alpha', 13, 10, 0
209Linux_GotBadKernel db ' - Bad Kernel/Bad FAT-16 partition', 0
210Linux_INT15error db ' - INT 15 error', 0
211Linux_RootDefine db 'root='
212
213LINUX_LoadKernel Proc Near Uses ; Direct Jump, No Preserves
214 ; TranslateToDev needs UNFILTERED Partition Pointers...
215 call PART_CalculateStraightPartPointers
216 push si
217 mov si, offset Linux_FuzzyString
218 call MBR_Teletype
219 pop si
220 ; DX - Starting-Cluster of Linux Kernel File
221 mov dx, ds:[si+LocIPT_LocationBegin]
222 ; from now on, we don't need si anymore
223
224 ; Linux has 1 'BR' (which is crap) and some setup sectors
225 ; we load them at 9000:0, what a luck, we are at 8000:0 :-))
226 push ds es
227 mov ax, 9000h
228 mov es, ax
229 xor di, di
230 call FAT16_ReadCluster ; Load First Cluster (DX) to 9000:0
231 mov cl, bptr es:[01F1h] ; Setup sectors to load
232 inc cl ; Total sectors to load to 9000:0
233 jmp LLL_CheckLeft
234
235 LLL_LoadSetupCodeLoop:
236 call FAT16_ReadCluster
237 LLL_CheckLeft:
238 sub cl, FAT16_SecsPerCluster
239 jz LLL_GotAllClusterDone
240 jc LLL_GotAllClusterNotEmpty
241 jmp LLL_LoadSetupCodeLoop
242
243 LLL_GotAllClusterDone:
244 xor cx, cx
245 jmp LLL_GotAll
246 LLL_GotAllClusterNotEmpty:
247 ; Damn, Cluster didn't got empty. So we have to copy the rest out...
248 xor ch, ch
249 not cl
250 inc cl ; 0FFh -> 1 sector to get...
251 ; Now copy rest to 6000:0 location for later processing...
252 ; ES:DI - Ending location of Setup Code
253 mov ax, 9000h
254 mov ds, ax
255 mov ax, 6000h
256 mov es, ax
257 push cx si ; Push Kernel-Entry-Pointer
258 mov si, di
259 shl cx, 9 ; Sectors to Byte Count
260 sub si, cx ; DS:SI - Begin of Kernel Data
261 xor di, di
262 shr cx, 1
263 rep movsw ; Copy Data...
264 pop si cx ; Get Kernel-Entry-Pointer back
265 LLL_GotAll:
266 pop es ds
267
268 push cx dx ; Push Missing-Sectors, StartCluster
269 mov ax, 9000h
270 mov ds, ax
271
272 ; Check Signatures for security...
273 cmp wptr ds:[1FEh], 0AA55h
274 jne LLL_BadKernel
275 cmp wptr ds:[202h], 'dH'
276 jne LLL_BadKernel
277 cmp wptr ds:[204h], 'Sr'
278 je LLL_GoodKernel
279 LLL_BadKernel:
280 push es
281 pop ds
282 mov si, offset Linux_GotBadKernel
283 call MBR_Teletype
284 jmp MBR_HaltSystem
285 LLL_GoodKernel:
286
287 ; Now we have at least some of the required sectors loaded
288 mov ax, 9000h
289 mov dx, ax
290 mov al, bptr ds:[01F1h] ; Setup Sectors to load
291 ; -> to 9020:0
292
293 ; Just append parameters to end of Linux boot-block...
294 xor ah, ah
295 mov bl, 20h
296 mul bl ; AX * 20
297 add dx, ax ; add to segment -> Segment of Parameters
298
299 mov wptr ds:[0020h], 0A33Fh
300 mov ax, dx
301 and ax, 0FFFh ; 9100h -> 0100h
302 shl ax, 4 ; 0100h -> 1000h
303 mov wptr ds:[0022h], ax ; offset of parameter relative 9000:0
304
305 ; fill out Linux-Loader byte, so SETUP will do its job
306 mov bptr ds:[0210h], 0A0h ; AiR-BOOT (unknown ID for Linux btw)
307 mov cx, wptr ds:[01F4h] ; Linux Kernel Length in 16-byte blocks
308 shr cx, 5
309 inc cx ; Convert to Sector-Count
310 push cx
311 push cs
312 pop ds ; CS == DS
313 mov es, dx ; ES = Segment for parameters
314 xor di, di ; ES:0 - Parameter Ptr
315 mov dl, cs:[CFG_LinuxRootPartition]
316 cmp dl, 0FFh
317 je LLL_NoRootPartitionFound
318 mov cx, 5
319 mov si, offset Linux_RootDefine
320 rep movsb ; root=
321 call LINUX_TranslateToDEV ; Writes DEV (dl) at ES:DI (/dev/hda9)
322
323 LLL_NoRootPartitionFound:
324 ; Root-Define complete, now for the user Kernel Command-Line...
325 mov si, offset CFG_LinuxCommandLine
326 mov al, ds:[si]
327 or al, al
328 jz LLL_CommandLineLoop
329 mov al, ' '
330 stosb ; If any command-line, insert space
331 LLL_CommandLineLoop:
332 lodsb
333 stosb ; Copy string till and including NUL
334 or al, al
335 jnz LLL_CommandLineLoop
336 stosb ; Write another NUL
337 pop cx
338 pop dx bx ; Pop StartCluster, Missing-Sectors
339 ; CX - Sector-Count of Kernel Image, DX - Starting Cluster of Kernel Image
340 ; BX - Sector-Count left over in 6000:0 area from Setup Code loading
341 ; DS == CS
342
343 ; Now comes some tricky part. Hopefully we have a tiny kernel.
344 ; If we have a big kernel, we have to 'upload' it to PM-memory space.
345 test bptr ds:[0211h], 01h
346 jz LLL_LoadNormalKernel
347 jmp LLL_LoadBigKernel
348
349 LLL_LoadNormalKernel:
350 ; NORMAL KERNEL
351
352 ; Still UNSUPPORTED. This suxxs
353
354 LLL_LoadBigKernel:
355 ; BIG KERNEL - Oh no, we have to load all data to extended memory...
356 mov ax, 6000h
357 mov es, ax
358 shr ax, 4
359 ; Set Source to 06:0000
360 mov bptr cs:[MBR_Linux_GDT_Src+0], al
361 mov wptr cs:[MBR_Linux_GDT_Src+1], ax
362 xor si, si
363 or bx, bx ; No unfinished Cluster ?
364 jz LLL_LoadBigKernelLoop
365 push cx
366 mov cx, bx
367 shl cx, 8 ; Sectors to WORD Count
368 call LINUX_MoveKernelPart ; Copy Data to Extended Memory
369 pop cx
370 LLL_LoadBigKernelLoop:
371 push cx
372 ; DX - Current Cluster
373 ; CX - Total WORDs that need to be loaded
374 ; ES - Segment
375 mov cx, 8000h
376 call LINUX_LoadDataToMemory
377 ; CX - Total WORDs that were loaded...
378 ; Got 6000:0 filled...
379 call LINUX_MoveKernelPart
380 shr cx, 8 ; WORDs to SEGMENTs
381 add si, cx
382 pop cx
383 cmp si, cx
384 jb LLL_LoadBigKernelLoop
385
386 LLL_FinishedLoadKernel:
387 ; either way, we give execution to setup at 9020:0
388 mov ax, 09020h
389 mov ss, ax
390 mov sp, 4000h-12h ; Linux wants it this way...
391 mov ds, ax
392 mov es, ax
393 db 0EAh
394 dw 0
395 dw 09020h
396LINUX_LoadKernel EndP
397
398; Loads Data from Cluster(s) to memory...
399; In: DX - First cluster to read from...
400; CX - Total WORDs that need to be loaded at least
401; ES - Segment, where to load to (Starting Offset is zero)
402; Out: CX - Total WORDs that got loaded
403; DX - Cluster following last loaded cluster
404; (buffer filled)
405; Destroyed: None
406; MUST BE USING CS for addressing Code Segment, DS =! CS
407LINUX_LoadDataToMemory Proc Near Uses di
408 shl cx, 1 ; Convert WORDs to BYTEs
409 dec cx ; 0000h -> FFFFh
410 xor di, di
411 LLDTM_LoadLoop:
412 call FAT16_ReadCluster ; Load Cluster DX to ES:DI
413 ; DX and DI were updated by ReadCluster, so don't modify them...
414 or di, di
415 jz LLDTM_Overflow
416 cmp di, cx
417 jbe LLDTM_LoadLoop
418 mov cx, di
419 shr cx, 1
420 inc cx ; 3FFFh -> 4000h
421 ret
422 LLDTM_Overflow:
423 mov cx, 08000h
424 ret
425LINUX_LoadDataToMemory EndP
426
427; Copies Extended-Memory (clobbered from Linux setup)
428; In: CX - Total WORDs to copy
429; Out: (buffer copied)
430; Destroyed: None
431; MUST BE USING CS for addressing Code Segment, DS =! CS
432LINUX_MoveKernelPart Proc Near Uses ax cx es si
433 mov ax, cs
434 mov es, ax
435 mov si, offset MBR_Linux_GDT
436 push cx
437 mov ax, 08700h
438; IFDEF ReleaseCode
439 int 15h
440 jc LMKP_Error
441; ENDIF
442 pop cx
443 ; now adjust Destination by copied word-count
444 add wptr cs:[MBR_Linux_GDT_Dst], cx
445 adc bptr cs:[MBR_Linux_GDT_Dst+2], 0
446 add wptr cs:[MBR_Linux_GDT_Dst], cx
447 adc bptr cs:[MBR_Linux_GDT_Dst+2], 0
448 ret
449 LMKP_Error:
450 mov ax, cs
451 mov ds, ax
452 mov si, offset Linux_INT15error
453 call MBR_Teletype
454 jmp MBR_HaltSystem
455LINUX_MoveKernelPart EndP
456
457MBR_Linux_GDT: dw 0, 0, 0, 0
458 dw 0, 0, 0, 0
459 dw 0FFFFh
460MBR_Linux_GDT_Src db 0, 0, 06h ; Source is 6000:0
461 db 093h
462 dw 0
463 dw 0FFFFh
464MBR_Linux_GDT_Dst db 0, 0, 10h ; Dest is "10000:0"
465 db 093h
466 dw 0
467 dw 0, 0, 0, 0
468 dw 0, 0, 0, 0
469 dw 0
470
471;
472; Example of boot setup command under lilo prompt:
473;
474; lilo: linux root=/dev/sda2 sym53c8xx=tags:4,sync:10,debug:0x200
475;
Note: See TracBrowser for help on using the repository browser.