Add more low-level API function to load the kernel, and make the
[profile/ivi/syslinux.git] / ui.inc
1 ;; $Id$
2 ;; -----------------------------------------------------------------------
3 ;;   
4 ;;   Copyright 1994-2002 H. Peter Anvin - All Rights Reserved
5 ;;
6 ;;   This program is free software; you can redistribute it and/or modify
7 ;;   it under the terms of the GNU General Public License as published by
8 ;;   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
9 ;;   Boston MA 02111-1307, USA; either version 2 of the License, or
10 ;;   (at your option) any later version; incorporated herein by reference.
11 ;;
12 ;; -----------------------------------------------------------------------
13
14 ;
15 ; This file should be entered with the config file open (for getc)
16 ;
17                 call parse_config               ; Parse configuration file
18 no_config_file:
19 ;
20 ; Check whether or not we are supposed to display the boot prompt.
21 ;
22 check_for_key:
23                 cmp word [ForcePrompt],0        ; Force prompt?
24                 jnz enter_command
25                 test byte [KbdFlags],5Bh        ; Shift Alt Caps Scroll
26                 jz auto_boot                    ; If neither, default boot
27
28 enter_command:
29                 cmp word [NoEscape],0           ; If NOESCAPE, no prompt,
30                 jne auto_boot                   ; always run default cmd
31
32                 mov si,boot_prompt
33                 call cwritestr
34
35                 mov byte [FuncFlag],0           ; <Ctrl-F> not pressed
36                 mov di,command_line
37 ;
38 ; get the very first character -- we can either time
39 ; out, or receive a character press at this time.  Some dorky BIOSes stuff
40 ; a return in the buffer on bootup, so wipe the keyboard buffer first.
41 ;
42 clear_buffer:   mov ah,11h                      ; Check for pending char
43                 int 16h
44                 jz get_char_time
45                 mov ah,10h                      ; Get char
46                 int 16h
47                 jmp short clear_buffer
48 get_char_time:  
49                 call vgashowcursor
50                 RESET_IDLE
51                 mov cx,[KbdTimeOut]
52                 and cx,cx
53                 jz get_char                     ; Timeout == 0 -> no timeout
54                 inc cx                          ; The first loop will happen
55                                                 ; immediately as we don't
56                                                 ; know the appropriate DX value
57 time_loop:      push cx
58 tick_loop:      push dx
59                 call pollchar
60                 jnz get_char_pop
61                 mov dx,[BIOS_timer]             ; Get time "of day"
62                 pop ax
63                 cmp dx,ax                       ; Has the timer advanced?
64                 je tick_loop
65                 pop cx
66                 DO_IDLE
67                 loop time_loop                  ; If so, decrement counter
68
69                 ; Timeout!!!!
70                 call vgahidecursor
71                 mov si,Ontimeout                ; Copy ontimeout command
72                 mov cx,[OntimeoutLen]           ; if we have one...
73                 rep movsb
74 .stddefault:
75                 jmp command_done
76
77 get_char_pop:   pop eax                         ; Clear stack
78 get_char:
79                 call vgashowcursor
80                 call getchar
81                 call vgahidecursor
82                 and al,al
83                 jz func_key
84
85 got_ascii:      cmp al,7Fh                      ; <DEL> == <BS>
86                 je backspace
87                 cmp al,' '                      ; ASCII?
88                 jb not_ascii
89                 ja enter_char
90                 cmp di,command_line             ; Space must not be first
91                 je short get_char
92 enter_char:     test byte [FuncFlag],1
93                 jz .not_ctrl_f
94                 mov byte [FuncFlag],0
95                 cmp al,'0'
96                 jb .not_ctrl_f
97                 je ctrl_f_0
98                 cmp al,'9'
99                 jbe ctrl_f
100 .not_ctrl_f:    cmp di,max_cmd_len+command_line ; Check there's space
101                 jnb short get_char
102                 stosb                           ; Save it
103                 call writechr                   ; Echo to screen
104                 jmp short get_char
105 not_ascii:      mov byte [FuncFlag],0
106                 cmp al,0Dh                      ; Enter
107                 je command_done
108                 cmp al,'F' & 1Fh                ; <Ctrl-F>
109                 je set_func_flag
110                 cmp al,'U' & 1Fh                ; <Ctrl-U>
111                 je kill_command                 ; Kill input line
112                 cmp al,'V' & 1Fh                ; <Ctrl-V>
113                 je print_version
114                 cmp al,'X' & 1Fh                ; <Ctrl-X>
115                 je force_text_mode
116                 cmp al,08h                      ; Backspace
117                 jne get_char
118 backspace:      cmp di,command_line             ; Make sure there is anything
119                 je get_char                     ; to erase
120                 dec di                          ; Unstore one character
121                 mov si,wipe_char                ; and erase it from the screen
122                 call cwritestr
123                 jmp short get_char_2
124
125 kill_command:
126                 call crlf
127                 jmp enter_command
128
129 force_text_mode:
130                 call vgaclearmode
131                 jmp enter_command
132
133 set_func_flag:
134                 mov byte [FuncFlag],1
135 get_char_2:
136                 jmp short get_char
137
138 ctrl_f_0:       add al,10                       ; <Ctrl-F>0 == F10
139 ctrl_f:         sub al,'1'
140                 xor ah,ah
141                 jmp short show_help
142
143 func_key:
144                 ; AL = 0 if we get here
145                 xchg al,ah
146                 cmp al,68                       ; F10
147                 ja short get_char_2
148                 sub al,59                       ; F1
149                 jb short get_char_2
150 show_help:      ; AX = func key # (0 = F1, 9 = F10)
151                 push di                         ; Save end-of-cmdline pointer
152                 shl ax,FILENAME_MAX_LG2         ; Convert to pointer
153                 add ax,FKeyName
154                 xchg di,ax
155                 cmp byte [di+NULLOFFSET],NULLFILE
156                 je short fk_nofile              ; Undefined F-key
157                 call searchdir
158                 jz short fk_nofile              ; File not found
159                 push si
160                 call crlf
161                 pop si
162                 call get_msg_file
163                 jmp short fk_wrcmd
164
165 print_version:
166                 push di                         ; Command line write pointer
167                 mov si,syslinux_banner
168                 call cwritestr
169 %ifdef HAVE_BIOSNAME
170                 mov si,[BIOSName]
171                 call cwritestr
172 %endif
173                 mov si,copyright_str
174                 call cwritestr
175
176                 ; ... fall through ...
177
178                 ; Write the boot prompt and command line again and
179                 ; wait for input.  Note that this expects the cursor
180                 ; to already have been CRLF'd, and that the old value
181                 ; of DI (the command line write pointer) is on the stack.
182 fk_wrcmd:
183                 mov si,boot_prompt
184                 call cwritestr
185                 pop di                          ; Command line write pointer
186                 push di
187                 mov byte [di],0                 ; Null-terminate command line
188                 mov si,command_line
189                 call cwritestr                  ; Write command line so far
190 fk_nofile:      pop di
191                 jmp short get_char_2
192
193 ;
194 ; Jump here to run the default command line
195 ;
196 auto_boot:
197                 mov si,default_cmd
198                 mov di,command_line
199                 mov cx,(max_cmd_len+4) >> 2
200                 rep movsd
201                 jmp short load_kernel
202
203 ;
204 ; Jump here when the command line is completed
205 ;
206 command_done:
207                 call crlf
208                 cmp di,command_line             ; Did we just hit return?
209                 je auto_boot
210                 xor al,al                       ; Store a final null
211                 stosb
212
213 load_kernel:                                    ; Load the kernel now
214 ;
215 ; First we need to mangle the kernel name the way DOS would...
216 ;
217                 mov si,command_line
218                 mov di,KernelName
219                 push si
220                 push di
221                 call mangle_name
222                 pop di
223                 pop si
224 ;
225 ; Fast-forward to first option (we start over from the beginning, since
226 ; mangle_name doesn't necessarily return a consistent ending state.)
227 ;
228 clin_non_wsp:   lodsb
229                 cmp al,' '
230                 ja clin_non_wsp
231 clin_is_wsp:    and al,al
232                 jz clin_opt_ptr
233                 lodsb
234                 cmp al,' '
235                 jbe clin_is_wsp
236 clin_opt_ptr:   dec si                          ; Point to first nonblank
237                 mov [CmdOptPtr],si              ; Save ptr to first option
238 ;
239 ; If "allowoptions 0", put a null character here in order to ignore any
240 ; user-specified options.
241 ;
242                 mov ax,[AllowOptions]
243                 and ax,ax
244                 jnz clin_opt_ok
245                 mov [si],al
246 clin_opt_ok:
247
248 ;
249 ; Now check if it is a "virtual kernel"
250 ;
251 vk_check:
252                 xor si,si                       ; Beginning of vk_seg
253 .scan:
254                 cmp si,[VKernelBytes]
255                 jae .not_vk
256
257                 push ds
258                 push word vk_seg
259                 pop ds
260
261                 mov di,VKernelBuf
262                 call rllunpack
263                 pop ds
264                 ; SI updated on return
265
266                 sub di,cx                       ; Return to beginning of buf
267                 push si
268                 mov si,KernelName
269                 mov cx,FILENAME_MAX
270                 es repe cmpsb
271                 pop si
272                 je .found
273                 jmp .scan
274
275 ;
276 ; We *are* using a "virtual kernel"
277 ;
278 .found:
279                 push es
280                 push word real_mode_seg
281                 pop es
282                 mov di,cmd_line_here
283                 mov si,VKernelBuf+vk_append
284                 mov cx,[VKernelBuf+vk_appendlen]
285                 rep movsb
286                 mov [CmdLinePtr],di             ; Where to add rest of cmd
287                 pop es
288                 mov di,KernelName
289                 push di 
290                 mov si,VKernelBuf+vk_rname
291                 mov cx,FILENAME_MAX             ; We need ECX == CX later
292                 rep movsb
293                 pop di
294 %if IS_PXELINUX
295                 mov al,[VKernelBuf+vk_ipappend]
296                 mov [IPAppend],al
297 %endif
298                 xor bx,bx                       ; Try only one version
299
300 %if IS_PXELINUX || IS_ISOLINUX
301                 ; Is this a "localboot" pseudo-kernel?
302 %if IS_PXELINUX
303                 cmp byte [VKernelBuf+vk_rname+4], 0
304 %else
305                 cmp byte [VKernelBuf+vk_rname], 0
306 %endif
307                 jne get_kernel          ; No, it's real, go get it
308
309                 mov ax, [VKernelBuf+vk_rname+1]
310                 jmp local_boot
311 %else
312                 jmp get_kernel
313 %endif
314
315 .not_vk:
316
317 ;
318 ; Not a "virtual kernel" - check that's OK and construct the command line
319 ;
320                 cmp word [AllowImplicit],byte 0
321                 je bad_implicit
322                 push es
323                 push si
324                 push di
325                 mov di,real_mode_seg
326                 mov es,di
327                 mov si,AppendBuf
328                 mov di,cmd_line_here
329                 mov cx,[AppendLen]
330                 rep movsb
331                 mov [CmdLinePtr],di
332                 pop di
333                 pop si
334                 pop es
335 ;
336 ; Find the kernel on disk
337 ;
338 get_kernel:     mov byte [KernelName+FILENAME_MAX],0    ; Zero-terminate filename/extension
339 %if IS_SYSLINUX || IS_MDSLINUX                  ; SYSLINUX has to deal with DOS mangled names...
340                 mov eax,[KernelName+8]          ; Save initial extension
341                 mov [exten_table_end],eax       ; Last case == initial ext.
342 %else
343                 mov di,KernelName+4*IS_PXELINUX
344                 xor al,al
345                 mov cx,FILENAME_MAX-5           ; Need 4 chars + null
346                 repne scasb                     ; Scan for final null
347                 jne .no_skip
348                 dec di                          ; Point to final null 
349 .no_skip:       mov [KernelExtPtr],di
350 %endif
351                 mov bx,exten_table
352 .search_loop:   push bx
353                 mov di,KernelName               ; Search on disk
354                 call searchdir
355                 pop bx
356                 jnz kernel_good
357                 mov eax,[bx]                    ; Try a different extension
358 %if IS_SYSLINUX || IS_MDSLINUX
359                 mov [KernelName+8],eax
360 %else
361                 mov si,[KernelExtPtr]
362                 mov [si],eax
363                 mov byte [si+4],0
364 %endif
365                 add bx,byte 4
366                 cmp bx,exten_table_end
367                 jna .search_loop                ; allow == case (final case)
368                 ; Fall into bad_kernel
369 ;
370 ; bad_kernel: Kernel image not found
371 ; bad_implicit: The user entered a nonvirtual kernel name, with "implicit 0"
372 ;
373 bad_implicit:
374 bad_kernel:
375                 mov cx,[OnerrorLen]
376                 and cx,cx
377                 jnz on_error
378 .really:
379                 mov si,KernelName
380                 mov di,KernelCName
381                 push di
382                 call unmangle_name              ; Get human form
383                 mov si,err_notfound             ; Complain about missing kernel
384                 call cwritestr
385                 pop si                          ; KernelCName
386                 call cwritestr
387                 mov si,crlf_msg
388                 jmp abort_load                  ; Ask user for clue
389
390 ;
391 ; on_error: bad kernel, but we have onerror set
392 ;
393 on_error:
394                 mov si,Onerror
395                 mov di,command_line
396                 push si                         ; <A>
397                 push di                         ; <B>
398                 push cx                         ; <C>
399                 push cx                         ; <D>
400                 push di                         ; <E>
401                 repe cmpsb
402                 pop di                          ; <E> di == command_line
403                 pop bx                          ; <D> bx == [OnerrorLen]
404                 je bad_kernel.really            ; Onerror matches command_line already
405                 neg bx                          ; bx == -[OnerrorLen]
406                 lea cx,[max_cmd_len+bx]
407                 ; CX == max_cmd_len-[OnerrorLen]
408                 mov di,command_line+max_cmd_len-1
409                 mov byte [di+1],0               ; Enforce null-termination
410                 lea si,[di+bx]
411                 std
412                 rep movsb                       ; Make space in command_line
413                 cld
414                 pop cx                          ; <C> cx == [OnerrorLen]
415                 pop di                          ; <B> di == command_line
416                 pop si                          ; <A> si  == Onerror
417                 rep movsb
418                 jmp load_kernel
419
420 ;
421 ; kernel_corrupt: Called if the kernel file does not seem healthy
422 ;
423 kernel_corrupt: mov si,err_notkernel
424                 jmp abort_load
425 ;
426 ; This is it!  We have a name (and location on the disk)... let's load
427 ; that sucker!!  First we have to decide what kind of file this is; base
428 ; that decision on the file extension.  The following extensions are
429 ; recognized; case insensitive:
430 ;
431 ; .com  - COMBOOT image
432 ; .cbt  - COMBOOT image
433 ; .c32  - COM32 image
434 ; .bs   - Boot sector
435 ; .0    - PXE bootstrap program (PXELINUX only)
436 ; .bin  - Boot sector
437 ; .bss  - Boot sector, but transfer over DOS superblock (SYSLINUX only)
438 ; .img  - Floppy image (ISOLINUX only)
439 ;
440 ; Anything else is assumed to be a Linux kernel.
441 ;
442                 section .bss
443                 alignb 4
444 Kernel_EAX      resd 1
445 Kernel_SI       resw 1
446
447                 section .text
448 kernel_good_saved:
449                 ; Alternate entry point for which the return from
450                 ; searchdir is stored in memory.  This is used for
451                 ; COMBOOT function INT 22h, AX=0016h.
452                 mov si,[Kernel_SI]
453                 mov eax,[Kernel_EAX]
454                 mov dx,[Kernel_EAX+2]
455
456 kernel_good:
457                 pusha
458                 mov si,KernelName
459                 mov di,KernelCName
460                 call unmangle_name
461                 sub di,KernelCName
462                 mov [KernelCNameLen],di
463                 popa
464                 
465 %if IS_SYSLINUX || IS_MDSLINUX
466                 mov ecx,[KernelName+7]
467                 mov cl,'.'
468 %else
469                 push di
470                 push ax
471                 mov di,KernelName+4*IS_PXELINUX
472                 xor al,al
473                 mov cx,FILENAME_MAX
474                 repne scasb
475                 jne .one_step
476                 dec di
477 .one_step:      mov ecx,[di-4]                  ; 4 bytes before end
478                 pop ax
479                 pop di
480 %endif
481
482 ;
483 ; At this point, DX:AX contains the size of the kernel, and SI contains
484 ; the file handle/cluster pointer.
485 ;
486                 or ecx,20202000h                ; Force lower case
487
488                 cmp ecx,'.com'
489                 je is_comboot_image
490                 cmp ecx,'.cbt'
491                 je is_comboot_image
492                 cmp ecx,'.c32'
493                 je is_com32_image
494 %if IS_ISOLINUX
495                 cmp ecx,'.img'
496                 je is_disk_image
497 %endif
498                 cmp ecx,'.bss'
499                 je is_bss_sector
500                 cmp ecx,'.bin'
501                 je is_bootsector
502 %if IS_SYSLINUX || IS_MDSLINUX
503                 cmp ecx,'.bs '
504                 je is_bootsector
505                 cmp ecx,'.0  '
506                 je is_bootsector
507 %else
508                 shr ecx,8
509                 cmp ecx,'.bs'
510                 je is_bootsector
511                 shr ecx,8
512                 cmp cx,'.0'
513                 je is_bootsector
514 %endif
515                 ; Otherwise Linux kernel
516
517                 section .bss
518                 alignb 2
519 KernelExtPtr    resw 1                  ; During search, final null pointer
520 CmdOptPtr       resw 1                  ; Pointer to first option on cmd line
521 KbdFlags        resb 1                  ; Check for keyboard escapes
522 FuncFlag        resb 1                  ; Escape sequences received from keyboard
523
524                 section .text