Initial support for auxilliary data vector
[profile/ivi/syslinux.git] / ui.inc
1 ;; -----------------------------------------------------------------------
2 ;;
3 ;;   Copyright 1994-2007 H. Peter Anvin - All Rights Reserved
4 ;;
5 ;;   This program is free software; you can redistribute it and/or modify
6 ;;   it under the terms of the GNU General Public License as published by
7 ;;   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
8 ;;   Boston MA 02111-1307, USA; either version 2 of the License, or
9 ;;   (at your option) any later version; incorporated herein by reference.
10 ;;
11 ;; -----------------------------------------------------------------------
12
13 ;
14 ; This file should be entered with the config file open (for getc)
15 ;
16 load_config_file:
17                 call parse_config               ; Parse configuration file
18 no_config_file:
19
20                 call adv_init
21
22 ;
23 ; Check whether or not we are supposed to display the boot prompt.
24 ;
25 check_for_key:
26                 cmp word [ForcePrompt],0        ; Force prompt?
27                 jnz enter_command
28                 test byte [KbdFlags],5Bh        ; Shift Alt Caps Scroll
29                 jz auto_boot                    ; If neither, default boot
30
31 enter_command:
32                 cmp word [NoEscape],0           ; If NOESCAPE, no prompt,
33                 jne auto_boot                   ; always run default cmd
34
35                 mov si,boot_prompt
36                 call cwritestr
37
38                 mov byte [FuncFlag],0           ; <Ctrl-F> not pressed
39                 mov di,command_line
40
41 ;
42 ; get the very first character -- we can either time
43 ; out, or receive a character press at this time.  Some dorky BIOSes stuff
44 ; a return in the buffer on bootup, so wipe the keyboard buffer first.
45 ;
46 clear_buffer:   mov ah,11h                      ; Check for pending char
47                 int 16h
48                 jz get_char_time
49                 mov ah,10h                      ; Get char
50                 int 16h
51                 jmp short clear_buffer
52
53                 ; For the first character, both KbdTimeout and
54                 ; TotalTimeout apply; after that, only TotalTimeout.
55
56 get_char_time:
57                 mov eax,[TotalTimeout]
58                 mov [ThisTotalTo],eax
59                 mov eax,[KbdTimeout]
60                 mov [ThisKbdTo],eax
61
62 get_char:
63                 call getchar_timeout
64                 and dword [ThisKbdTo],0         ; For the next time...
65
66                 and al,al
67                 jz func_key
68
69 got_ascii:      cmp al,7Fh                      ; <DEL> == <BS>
70                 je backspace
71                 cmp al,' '                      ; ASCII?
72                 jb not_ascii
73                 ja enter_char
74                 cmp di,command_line             ; Space must not be first
75                 je short get_char
76 enter_char:     test byte [FuncFlag],1
77                 jnz ctrl_f                      ; Keystroke after <Ctrl-F>
78                 cmp di,max_cmd_len+command_line ; Check there's space
79                 jnb short get_char
80                 stosb                           ; Save it
81                 call writechr                   ; Echo to screen
82                 jmp short get_char
83 not_ascii:
84                 cmp al,0Dh                      ; Enter
85                 je command_done
86                 cmp al,'F' & 1Fh                ; <Ctrl-F>
87                 je set_func_flag
88 %if IS_PXELINUX
89                 cmp al,'N' & 1Fh                ; <Ctrl-N>
90                 je show_network_info
91 %endif
92                 cmp al,'U' & 1Fh                ; <Ctrl-U>
93                 je kill_command                 ; Kill input line
94                 cmp al,'V' & 1Fh                ; <Ctrl-V>
95                 je print_version
96                 cmp al,'X' & 1Fh                ; <Ctrl-X>
97                 je force_text_mode
98                 cmp al,08h                      ; Backspace
99                 jne get_char
100 backspace:      cmp di,command_line             ; Make sure there is anything
101                 je get_char                     ; to erase
102                 dec di                          ; Unstore one character
103                 mov si,wipe_char                ; and erase it from the screen
104                 call cwritestr
105 get_char_2:
106                 jmp short get_char
107
108 kill_command:
109                 call crlf
110                 jmp enter_command
111
112 force_text_mode:
113                 call vgaclearmode
114                 jmp enter_command
115
116 set_func_flag:
117                 mov byte [FuncFlag],1
118                 jmp short get_char_2
119
120 ctrl_f:
121                 xor ah,ah
122                 mov [FuncFlag],ah
123                 cmp al,'0'
124                 jb get_char_2
125                 je .zero                        ; <Ctrl-F>0 = F10
126                 or al,20h                       ; Lower case
127                 cmp al,'9'
128                 jna .digit
129                 cmp al,'a'                      ; F10-F12 = <Ctrl-F>A, B, C
130                 jb get_char_2
131                 cmp al,'c'
132                 ja get_char_2
133                 sub al,'a'-10
134                 jmp show_help
135 .zero:
136                 mov al,10
137                 jmp show_help
138 .digit:
139                 sub al,'1'
140                 jmp show_help
141
142 func_key:
143                 ; AL = 0 if we get here
144                 xchg al,ah
145                 cmp al,44h                      ; F10
146                 ja .f11_f12
147                 sub al,3Bh                      ; F1
148                 jb get_char_2
149                 jmp show_help
150 .f11_f12:
151                 cmp al,85h                      ; F11
152                 jb get_char_2
153                 cmp al,86h                      ; F12
154                 ja get_char_2
155                 sub al,85h-10
156
157 show_help:      ; AX = func key # (0 = F1, 9 = F10, 11 = F12)
158                 push di                         ; Save end-of-cmdline pointer
159                 shl ax,FILENAME_MAX_LG2         ; Convert to pointer
160                 add ax,FKeyName
161                 xchg di,ax
162                 cmp byte [di+NULLOFFSET],NULLFILE
163                 je short fk_nofile              ; Undefined F-key
164                 call searchdir
165                 jz short fk_nofile              ; File not found
166                 push si
167                 call crlf
168                 pop si
169                 call get_msg_file
170                 jmp short fk_wrcmd
171
172 print_version:
173                 push di                         ; Command line write pointer
174                 mov si,syslinux_banner
175                 call cwritestr
176 %ifdef HAVE_BIOSNAME
177                 mov si,[BIOSName]
178                 call cwritestr
179 %endif
180                 mov si,copyright_str
181                 call cwritestr
182
183                 ; ... fall through ...
184
185                 ; Write the boot prompt and command line again and
186                 ; wait for input.  Note that this expects the cursor
187                 ; to already have been CRLF'd, and that the old value
188                 ; of DI (the command line write pointer) is on the stack.
189 fk_wrcmd:
190                 mov si,boot_prompt
191                 call cwritestr
192                 pop di                          ; Command line write pointer
193                 push di
194                 mov byte [di],0                 ; Null-terminate command line
195                 mov si,command_line
196                 call cwritestr                  ; Write command line so far
197 fk_nofile:      pop di
198                 jmp get_char
199
200 ;
201 ; Show network info (in the form of the ipappend strings)
202 ;
203 %if IS_PXELINUX
204 show_network_info:
205                 push di                         ; Command line write pointer
206                 call crlf
207                 mov si,IPAppends                ; See comboot.doc
208                 mov cx,numIPAppends
209 .loop:
210                 lodsw
211                 push si
212                 mov si,ax
213                 call cwritestr
214                 call crlf
215                 pop si
216                 loop .loop
217                 jmp fk_wrcmd
218 %endif
219
220 ;
221 ; Jump here to run the default command line
222 ;
223 auto_boot:
224                 mov si,default_cmd
225                 mov di,command_line
226                 mov cx,(max_cmd_len+4) >> 2
227                 rep movsd
228                 jmp short load_kernel
229
230 ;
231 ; Jump here when the command line is completed
232 ;
233 command_done:
234                 call crlf
235                 cmp di,command_line             ; Did we just hit return?
236                 je auto_boot
237                 xor al,al                       ; Store a final null
238                 stosb
239
240 load_kernel:                                    ; Load the kernel now
241 ;
242 ; First we need to mangle the kernel name the way DOS would...
243 ;
244                 mov si,command_line
245                 mov di,KernelName
246                 push si
247                 call mangle_name
248                 pop si
249 ;
250 ; Fast-forward to first option (we start over from the beginning, since
251 ; mangle_name doesn't necessarily return a consistent ending state.)
252 ;
253 clin_non_wsp:   lodsb
254                 cmp al,' '
255                 ja clin_non_wsp
256 clin_is_wsp:    and al,al
257                 jz clin_opt_ptr
258                 lodsb
259                 cmp al,' '
260                 jbe clin_is_wsp
261 clin_opt_ptr:   dec si                          ; Point to first nonblank
262                 mov [CmdOptPtr],si              ; Save ptr to first option
263 ;
264 ; If "allowoptions 0", put a null character here in order to ignore any
265 ; user-specified options.
266 ;
267                 mov ax,[AllowOptions]
268                 and ax,ax
269                 jnz clin_opt_ok
270                 mov [si],al
271 clin_opt_ok:
272
273 ;
274 ; Now check if it is a "virtual kernel"
275 ;
276 vk_check:
277                 xor si,si                       ; Beginning of vk_seg
278 .scan:
279                 cmp si,[VKernelBytes]
280                 jae .not_vk
281
282                 push ds
283                 push word vk_seg
284                 pop ds
285
286                 mov di,VKernelBuf
287                 call rllunpack
288                 pop ds
289                 ; SI updated on return
290
291                 sub di,cx                       ; Return to beginning of buf
292                 push si
293                 mov si,KernelName
294                 mov cx,FILENAME_MAX
295                 es repe cmpsb
296                 pop si
297                 je .found
298                 jmp .scan
299
300 ;
301 ; We *are* using a "virtual kernel"
302 ;
303 .found:
304                 push es
305                 push word real_mode_seg
306                 pop es
307                 mov di,cmd_line_here
308                 mov si,VKernelBuf+vk_append
309                 mov cx,[VKernelBuf+vk_appendlen]
310                 rep movsb
311                 mov [CmdLinePtr],di             ; Where to add rest of cmd
312                 pop es
313                 mov di,KernelName
314                 push di
315                 mov si,VKernelBuf+vk_rname
316                 mov cx,FILENAME_MAX             ; We need ECX == CX later
317                 rep movsb
318                 pop di
319 %if IS_PXELINUX
320                 mov al,[VKernelBuf+vk_ipappend]
321                 mov [IPAppend],al
322 %endif
323                 xor bx,bx                       ; Try only one version
324
325                 mov al, [VKernelBuf+vk_type]
326                 mov [KernelType], al
327
328 %if IS_PXELINUX || IS_ISOLINUX
329                 ; Is this a "localboot" pseudo-kernel?
330 %if IS_PXELINUX
331                 cmp byte [VKernelBuf+vk_rname+4], 0
332 %else
333                 cmp byte [VKernelBuf+vk_rname], 0
334 %endif
335                 jne get_kernel          ; No, it's real, go get it
336
337                 mov ax, [VKernelBuf+vk_rname+1]
338                 jmp local_boot
339 %else
340                 jmp get_kernel
341 %endif
342
343 .not_vk:
344
345 ;
346 ; Not a "virtual kernel" - check that's OK and construct the command line
347 ;
348                 cmp word [AllowImplicit],byte 0
349                 je bad_implicit
350                 push es
351                 push si
352                 push di
353                 mov di,real_mode_seg
354                 mov es,di
355                 mov si,AppendBuf
356                 mov di,cmd_line_here
357                 mov cx,[AppendLen]
358                 rep movsb
359                 mov [CmdLinePtr],di
360                 pop di
361                 pop si
362                 pop es
363
364                 mov [KernelType], cl            ; CL == 0 here
365
366 ;
367 ; Find the kernel on disk
368 ;
369 get_kernel:     mov byte [KernelName+FILENAME_MAX],0    ; Zero-terminate filename/extension
370                 mov di,KernelName+4*IS_PXELINUX
371                 xor al,al
372                 mov cx,FILENAME_MAX-5           ; Need 4 chars + null
373                 repne scasb                     ; Scan for final null
374                 jne .no_skip
375                 dec di                          ; Point to final null
376 .no_skip:       mov [KernelExtPtr],di
377                 mov bx,exten_table
378 .search_loop:   push bx
379                 mov di,KernelName               ; Search on disk
380                 call searchdir
381                 pop bx
382                 jnz kernel_good
383                 mov eax,[bx]                    ; Try a different extension
384                 mov si,[KernelExtPtr]
385                 mov [si],eax
386                 mov byte [si+4],0
387                 add bx,byte 4
388                 cmp bx,exten_table_end
389                 jna .search_loop                ; allow == case (final case)
390                 ; Fall into bad_kernel
391 ;
392 ; bad_kernel: Kernel image not found
393 ; bad_implicit: The user entered a nonvirtual kernel name, with "implicit 0"
394 ;
395 bad_implicit:
396 bad_kernel:
397                 mov cx,[OnerrorLen]
398                 and cx,cx
399                 jnz on_error
400 .really:
401                 mov si,KernelName
402                 mov di,KernelCName
403                 push di
404                 call unmangle_name              ; Get human form
405                 mov si,err_notfound             ; Complain about missing kernel
406                 call cwritestr
407                 pop si                          ; KernelCName
408                 call cwritestr
409                 mov si,crlf_msg
410                 jmp abort_load                  ; Ask user for clue
411
412 ;
413 ; on_error: bad kernel, but we have onerror set; CX = OnerrorLen
414 ;
415 on_error:
416                 mov si,Onerror
417                 mov di,command_line
418                 push si                         ; <A>
419                 push di                         ; <B>
420                 push cx                         ; <C>
421                 push cx                         ; <D>
422                 push di                         ; <E>
423                 repe cmpsb
424                 pop di                          ; <E> di == command_line
425                 pop bx                          ; <D> bx == [OnerrorLen]
426                 je bad_kernel.really            ; Onerror matches command_line already
427                 neg bx                          ; bx == -[OnerrorLen]
428                 lea cx,[max_cmd_len+bx]
429                 ; CX == max_cmd_len-[OnerrorLen]
430                 mov di,command_line+max_cmd_len-1
431                 mov byte [di+1],0               ; Enforce null-termination
432                 lea si,[di+bx]
433                 std
434                 rep movsb                       ; Make space in command_line
435                 cld
436                 pop cx                          ; <C> cx == [OnerrorLen]
437                 pop di                          ; <B> di == command_line
438                 pop si                          ; <A> si  == Onerror
439                 rep movsb
440                 jmp load_kernel
441
442 ;
443 ; kernel_corrupt: Called if the kernel file does not seem healthy
444 ;
445 kernel_corrupt: mov si,err_notkernel
446                 jmp abort_load
447
448 ;
449 ; Get a key, observing ThisKbdTO and ThisTotalTO -- those are timeouts
450 ; which can be adjusted by the caller based on the corresponding
451 ; master variables; on return they're updated.
452 ;
453 ; This cheats.  If we say "no timeout" we actually get a timeout of
454 ; 7.5 years.
455 ;
456 getchar_timeout:
457                 call vgashowcursor
458                 RESET_IDLE
459
460 .loop:
461                 push word [BIOS_timer]
462                 call pollchar
463                 jnz .got_char
464                 pop ax
465                 cmp ax,[BIOS_timer]             ; Has the timer advanced?
466                 je .loop
467                 DO_IDLE
468
469                 dec dword [ThisKbdTo]
470                 jz .timeout
471                 dec dword [ThisTotalTo]
472                 jnz .loop
473
474 .timeout:
475                 ; Timeout!!!!
476                 pop cx                          ; Discard return address
477                 call vgahidecursor
478                 mov si,Ontimeout                ; Copy ontimeout command
479                 mov di,command_line
480                 mov cx,[OntimeoutLen]           ; if we have one...
481                 rep movsb
482                 jmp command_done
483
484 .got_char:
485                 pop cx                          ; Discard
486                 call getchar
487                 call vgahidecursor
488                 ret
489
490 ;
491 ; This is it!  We have a name (and location on the disk)... let's load
492 ; that sucker!!  First we have to decide what kind of file this is; base
493 ; that decision on the file extension.  The following extensions are
494 ; recognized; case insensitive:
495 ;
496 ; .com  - COMBOOT image
497 ; .cbt  - COMBOOT image
498 ; .c32  - COM32 image
499 ; .bs   - Boot sector
500 ; .0    - PXE bootstrap program (PXELINUX only)
501 ; .bin  - Boot sector
502 ; .bss  - Boot sector, but transfer over DOS superblock (SYSLINUX only)
503 ; .img  - Floppy image (ISOLINUX only)
504 ;
505 ; Anything else is assumed to be a Linux kernel.
506 ;
507                 section .bss
508                 alignb 4
509 Kernel_EAX      resd 1
510 Kernel_SI       resw 1
511
512                 section .text
513 kernel_good_saved:
514                 ; Alternate entry point for which the return from
515                 ; searchdir is stored in memory.  This is used for
516                 ; COMBOOT function INT 22h, AX=0016h.
517                 mov si,[Kernel_SI]
518                 mov eax,[Kernel_EAX]
519                 mov dx,[Kernel_EAX+2]
520
521 kernel_good:
522                 pusha
523                 mov si,KernelName
524                 mov di,KernelCName
525                 call unmangle_name
526                 sub di,KernelCName
527                 mov [KernelCNameLen],di
528                 popa
529
530                 push di
531                 push ax
532                 mov di,KernelName+4*IS_PXELINUX
533                 xor al,al
534                 mov cx,FILENAME_MAX
535                 repne scasb
536                 jne .one_step
537                 dec di
538 .one_step:      mov ecx,[di-4]                  ; 4 bytes before end
539                 pop ax
540                 pop di
541
542 ;
543 ; At this point, DX:AX contains the size of the kernel, SI contains
544 ; the file handle/cluster pointer, and ECX contains the extension (if any.)
545 ;
546                 movzx di,byte [KernelType]
547                 add di,di
548                 jmp [kerneltype_table+di]
549
550 is_unknown_filetype:
551                 or ecx,20202000h                ; Force lower case (except dot)
552
553                 cmp ecx,'.com'
554                 je is_comboot_image
555                 cmp ecx,'.cbt'
556                 je is_comboot_image
557                 cmp ecx,'.c32'
558                 je is_com32_image
559 %if IS_ISOLINUX
560                 cmp ecx,'.img'
561                 je is_disk_image
562 %endif
563                 cmp ecx,'.bss'
564                 je is_bss_sector
565                 cmp ecx,'.bin'
566                 je is_bootsector
567                 shr ecx,8
568                 cmp ecx,'.bs'
569                 je is_bootsector
570                 shr ecx,8
571                 cmp cx,'.0'
572                 je is_bootsector
573
574                 ; Otherwise Linux kernel
575                 jmp is_linux_kernel
576
577 is_config_file:
578                 pusha
579                 mov si,KernelCName              ; Save the config file name, for posterity
580                 mov di,ConfigName
581                 call strcpy
582                 popa
583                 call openfd
584                 call reset_config
585                 jmp load_config_file
586
587 ; This is an image type we can't deal with
588 is_bad_image:
589                 mov si,err_badimage
590                 call cwritestr
591                 jmp enter_command
592
593 %if IS_SYSLINUX || IS_MDSLINUX
594                 ; ok
595 %else
596 is_bss_sector   equ is_bad_image
597 %endif
598 %if IS_ISOLINUX
599                 ; ok
600 %else
601 is_disk_image   equ is_bad_image
602 %endif
603
604                 section .data
605 boot_prompt     db 'boot: ', 0
606 wipe_char       db BS, ' ', BS, 0
607 err_badimage    db 'Invalid image type for this media type!', CR, LF, 0
608 err_notfound    db 'Could not find kernel image: ',0
609 err_notkernel   db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0
610
611
612                 align 2, db 0
613 kerneltype_table:
614                 dw is_unknown_filetype  ; VK_KERNEL
615                 dw is_linux_kernel      ; VK_LINUX
616                 dw is_bootsector        ; VK_BOOT
617                 dw is_bss_sector        ; VK_BSS
618                 dw is_bootsector        ; VK_PXE
619                 dw is_disk_image        ; VK_FDIMAGE
620                 dw is_comboot_image     ; VK_COMBOOT
621                 dw is_com32_image       ; VK_COM32
622                 dw is_config_file       ; VK_CONFIG
623
624                 section .bss
625                 alignb 4
626 ThisKbdTo       resd 1                  ; Temporary holder for KbdTimeout
627 ThisTotalTo     resd 1                  ; Temporary holder for TotalTimeout
628 KernelExtPtr    resw 1                  ; During search, final null pointer
629 CmdOptPtr       resw 1                  ; Pointer to first option on cmd line
630 KbdFlags        resb 1                  ; Check for keyboard escapes
631 FuncFlag        resb 1                  ; Escape sequences received from keyboard
632 KernelType      resb 1                  ; Kernel type, from vkernel, if known
633
634                 section .text
635 ;
636 ; Linux kernel loading code is common.
637 ;
638 %include "runkernel.inc"
639
640 ;
641 ; COMBOOT-loading code
642 ;
643 %include "comboot.inc"
644 %include "com32.inc"
645 %include "cmdline.inc"
646
647 ;
648 ; Boot sector loading code
649 ;
650 %include "bootsect.inc"
651
652 ;
653 ; Abort loading code
654 ;
655 %include "abort.inc"
656
657 ;
658 ; Hardware cleanup common code
659 ;
660 %include "cleanup.inc"