From patchwork Fri Apr 15 12:33:14 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Daniel Kiper X-Patchwork-Id: 8850781 Return-Path: X-Original-To: patchwork-xen-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 3F880C0553 for ; Fri, 15 Apr 2016 12:36:42 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 31CAB202E9 for ; Fri, 15 Apr 2016 12:36:40 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 43500202EB for ; Fri, 15 Apr 2016 12:36:38 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ar2xC-0005VE-Cc; Fri, 15 Apr 2016 12:34:30 +0000 Received: from mail6.bemta6.messagelabs.com ([85.158.143.247]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ar2xB-0005TH-0E for xen-devel@lists.xenproject.org; Fri, 15 Apr 2016 12:34:29 +0000 Received: from [85.158.143.35] by server-3.bemta-6.messagelabs.com id 20/BF-07120-4DFD0175; Fri, 15 Apr 2016 12:34:28 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFrrAIsWRWlGSWpSXmKPExsUyZ7p8oO7l+wL hBv2TjS2+b5nM5MDocfjDFZYAxijWzLyk/IoE1ozzr6+yFnw/w1ix+OxD9gbGa52MXYxcHEIC E5kkXuy4yw7h/GaU2LnjDzOEs4FRYseFH1CZiYwSTWsPsXUxcnKwCehIXPzykB3EFhFQkri3a jITSBGzwHkmiWmdl1lAEsICRRIPPn5jBbFZBFQl9nYfZQKxeQU8JDa8W8MIYksIKEp0P5sANp QTKL66swmolwNom7vEv6kiEOWCEidnPgELMwuoS6yfJwQSZhaQl2jeOpsZYoqhxOeNS5knMAr OQtIxC6FjFpKOBYzMqxjVi1OLylKLdA31kooy0zNKchMzc3QNDcz0clOLixPTU3MSk4r1kvNz NzECQ5cBCHYw7nzudIhRkoNJSZR37l6BcCG+pPyUyozE4oz4otKc1OJDjDIcHEoSvE/uAeUEi 1LTUyvSMnOAUQSTluDgURLhfQmS5i0uSMwtzkyHSJ1i1OU4NvfGWiYhlrz8vFQpcd73IEUCIE UZpXlwI2ARfYlRVkqYlxHoKCGegtSi3MwSVPlXjOIcjErCvK9BpvBk5pXAbXoFdAQT0BFl73h BjihJREhJNTDG+O3iSNZ9opmcsOgb3+z/r7bEdklbm/q+9PyVPufv7iUHPP81Tq1YwXXt0bl0 x2v8S/X2PMmdxrJ5plRst8ihdT2Z3YGR87K+vrlaKZAt8Mrw4p/7Wf+tlHoO1pyIOnhPY+P3S clTeX+vj/jfaznJ76/XUfNZj9QZ7hxMZ17//5vM49XbLyh6KLEUZyQaajEXFScCAH11rDjjAg AA X-Env-Sender: daniel.kiper@oracle.com X-Msg-Ref: server-10.tower-21.messagelabs.com!1460723665!9459292!1 X-Originating-IP: [156.151.31.81] X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: VHJ1c3RlZCBJUDogMTU2LjE1MS4zMS44MSA9PiAyODgzMzk=\n X-StarScan-Received: X-StarScan-Version: 8.28; banners=-,-,- X-VirusChecked: Checked Received: (qmail 12276 invoked from network); 15 Apr 2016 12:34:27 -0000 Received: from userp1040.oracle.com (HELO userp1040.oracle.com) (156.151.31.81) by server-10.tower-21.messagelabs.com with DHE-RSA-AES256-GCM-SHA384 encrypted SMTP; 15 Apr 2016 12:34:27 -0000 Received: from userv0022.oracle.com (userv0022.oracle.com [156.151.31.74]) by userp1040.oracle.com (Sentrion-MTA-4.3.2/Sentrion-MTA-4.3.2) with ESMTP id u3FCYLTA023476 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Fri, 15 Apr 2016 12:34:21 GMT Received: from userv0122.oracle.com (userv0122.oracle.com [156.151.31.75]) by userv0022.oracle.com (8.14.4/8.13.8) with ESMTP id u3FCYKGX006029 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Fri, 15 Apr 2016 12:34:20 GMT Received: from abhmp0003.oracle.com (abhmp0003.oracle.com [141.146.116.9]) by userv0122.oracle.com (8.14.4/8.14.4) with ESMTP id u3FCYKrE010079; Fri, 15 Apr 2016 12:34:20 GMT Received: from olila.local.net-space.pl (/10.175.160.106) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Fri, 15 Apr 2016 05:34:19 -0700 From: Daniel Kiper To: xen-devel@lists.xenproject.org Date: Fri, 15 Apr 2016 14:33:14 +0200 Message-Id: <1460723596-13261-15-git-send-email-daniel.kiper@oracle.com> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1460723596-13261-1-git-send-email-daniel.kiper@oracle.com> References: <1460723596-13261-1-git-send-email-daniel.kiper@oracle.com> MIME-Version: 1.0 X-Source-IP: userv0022.oracle.com [156.151.31.74] Cc: jgross@suse.com, andrew.cooper3@citrix.com, stefano.stabellini@eu.citrix.com, cardoe@cardoe.com, pgnet.dev@gmail.com, ning.sun@intel.com, david.vrabel@citrix.com, jbeulich@suse.com, qiaowei.ren@intel.com, richard.l.maliszewski@intel.com, gang.wei@intel.com, fu.wei@linaro.org Subject: [Xen-devel] =?utf-8?q?=5BPATCH_v3_14/16=5D_x86/boot=3A_implement_?= =?utf-8?q?early_command_line_parser_in_C?= X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Current early command line parser implementation in assembler is very difficult to change to relocatable stuff using segment registers. This requires a lot of changes in very weird and fragile code. So, reimplement this functionality in C. This way code will be relocatable out of the box (without playing with segment registers) and much easier to maintain. Suggested-by: Andrew Cooper Signed-off-by: Daniel Kiper --- v3 - suggestions/fixes: - optimize some code (suggested by Jan Beulich), - put VESA data into early_boot_opts_t members (suggested by Jan Beulich), - rename some functions and variables (suggested by Jan Beulich), - move around video.h include in xen/arch/x86/boot/trampoline.S (suggested by Jan Beulich), - fix coding style (suggested by Jan Beulich), - fix build with older GCC (suggested by Konrad Rzeszutek Wilk), - remove redundant comments (suggested by Jan Beulich), - add some comments - improve commit message (suggested by Jan Beulich). --- .gitignore | 5 +- xen/arch/x86/Makefile | 2 +- xen/arch/x86/boot/Makefile | 7 +- xen/arch/x86/boot/build32.lds | 1 + xen/arch/x86/boot/build32.mk | 4 +- xen/arch/x86/boot/cmdline.S | 367 ---------------------------------------- xen/arch/x86/boot/cmdline.c | 357 ++++++++++++++++++++++++++++++++++++++ xen/arch/x86/boot/edd.S | 3 - xen/arch/x86/boot/head.S | 17 ++ xen/arch/x86/boot/trampoline.S | 12 ++ xen/arch/x86/boot/video.S | 6 - 11 files changed, 400 insertions(+), 381 deletions(-) delete mode 100644 xen/arch/x86/boot/cmdline.S create mode 100644 xen/arch/x86/boot/cmdline.c diff --git a/.gitignore b/.gitignore index 91f690c..6919546 100644 --- a/.gitignore +++ b/.gitignore @@ -237,9 +237,10 @@ xen/arch/arm/xen.lds xen/arch/x86/asm-offsets.s xen/arch/x86/boot/mkelf32 xen/arch/x86/xen.lds +xen/arch/x86/boot/cmdline.S xen/arch/x86/boot/reloc.S -xen/arch/x86/boot/reloc.bin -xen/arch/x86/boot/reloc.lnk +xen/arch/x86/boot/*.bin +xen/arch/x86/boot/*.lnk xen/arch/x86/efi.lds xen/arch/x86/efi/check.efi xen/arch/x86/efi/disabled diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index 1bcb08b..32d2407 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -176,4 +176,4 @@ clean:: rm -f asm-offsets.s *.lds boot/*.o boot/*~ boot/core boot/mkelf32 rm -f $(BASEDIR)/.xen-syms.[0-9]* boot/.*.d rm -f $(BASEDIR)/.xen.efi.[0-9]* efi/*.o efi/.*.d efi/*.efi efi/disabled efi/mkreloc - rm -f boot/reloc.S boot/reloc.lnk boot/reloc.bin + rm -f boot/cmdline.S boot/reloc.S boot/*.lnk boot/*.bin diff --git a/xen/arch/x86/boot/Makefile b/xen/arch/x86/boot/Makefile index 06893d8..d73cc76 100644 --- a/xen/arch/x86/boot/Makefile +++ b/xen/arch/x86/boot/Makefile @@ -1,9 +1,14 @@ obj-bin-y += head.o +CMDLINE_DEPS = video.h + RELOC_DEPS = $(BASEDIR)/include/asm-x86/config.h $(BASEDIR)/include/xen/multiboot.h \ $(BASEDIR)/include/xen/multiboot2.h -head.o: reloc.S +head.o: cmdline.S reloc.S + +cmdline.S: cmdline.c $(CMDLINE_DEPS) + $(MAKE) -f build32.mk $@ CMDLINE_DEPS="$(CMDLINE_DEPS)" reloc.S: reloc.c $(RELOC_DEPS) $(MAKE) -f build32.mk $@ RELOC_DEPS="$(RELOC_DEPS)" diff --git a/xen/arch/x86/boot/build32.lds b/xen/arch/x86/boot/build32.lds index 47db9c4..6a234ea 100644 --- a/xen/arch/x86/boot/build32.lds +++ b/xen/arch/x86/boot/build32.lds @@ -25,6 +25,7 @@ SECTIONS *(.text) *(.text.*) *(.rodata) + *(.rodata.*) } /DISCARD/ : { diff --git a/xen/arch/x86/boot/build32.mk b/xen/arch/x86/boot/build32.mk index eb02b4b..58e27e1 100644 --- a/xen/arch/x86/boot/build32.mk +++ b/xen/arch/x86/boot/build32.mk @@ -23,7 +23,7 @@ CFLAGS := $(filter-out -flto,$(CFLAGS)) $(OBJDUMP) -h $< | sed -n '/[0-9]/{s,00*,0,g;p;}' |\ while read idx name sz rest; do \ case "$$name" in \ - .data|.data.*|.rodata.*|.bss|.bss.*) \ + .data|.data.*|.bss|.bss.*) \ test $$sz != 0 || continue; \ echo "Error: non-empty $$name: 0x$$sz" >&2; \ exit $$(expr $$idx + 1);; \ @@ -34,6 +34,8 @@ CFLAGS := $(filter-out -flto,$(CFLAGS)) %.o: %.c $(CC) $(CFLAGS) -c -fpic $< -o $@ +cmdline.o: cmdline.c $(CMDLINE_DEPS) + reloc.o: reloc.c $(RELOC_DEPS) .PRECIOUS: %.bin %.lnk diff --git a/xen/arch/x86/boot/cmdline.S b/xen/arch/x86/boot/cmdline.S deleted file mode 100644 index 00687eb..0000000 --- a/xen/arch/x86/boot/cmdline.S +++ /dev/null @@ -1,367 +0,0 @@ -/****************************************************************************** - * cmdline.S - * - * Early command-line parsing. - */ - - .code32 - -#include "video.h" - -# NB. String pointer on stack is modified to point past parsed digits. -.Latoi: - push %ebx - push %ecx - push %edx - push %esi - xor %ebx,%ebx /* %ebx = accumulator */ - mov $10,%ecx /* %ecx = base (default base 10) */ - mov 16+4(%esp),%esi /* %esi = pointer into ascii string. */ - lodsb - cmpb $'0',%al - jne 2f - mov $8,%ecx /* Prefix '0' => octal (base 8) */ - lodsb - cmpb $'x',%al - jne 2f - mov $16,%ecx /* Prefix '0x' => hex (base 16) */ -1: lodsb -2: sub $'0',%al - jb 4f - cmp $9,%al - jbe 3f - sub $'A'-'0'-10,%al - jb 4f - cmp $15,%al - jbe 3f - sub $'a'-'A',%al - jb 4f -3: cmp %cl,%al - jae 4f - movzbl %al,%eax - xchg %eax,%ebx - mul %ecx - xchg %eax,%ebx - add %eax,%ebx - jmp 1b -4: mov %ebx,%eax - dec %esi - mov %esi,16+4(%esp) - pop %esi - pop %edx - pop %ecx - pop %ebx - ret - -.Lstrstr: - push %ecx - push %edx - push %esi - push %edi - xor %eax,%eax - xor %ecx,%ecx - not %ecx - mov 16+4(%esp),%esi - mov 16+8(%esp),%edi - repne scasb - not %ecx - dec %ecx - mov %ecx,%edx -1: mov 16+8(%esp),%edi - mov %esi,%eax - mov %edx,%ecx - repe cmpsb - je 2f - xchg %eax,%esi - inc %esi - cmpb $0,-1(%eax) - jne 1b - xor %eax,%eax -2: pop %edi - pop %esi - pop %edx - pop %ecx - ret - -.Lstr_prefix: - push %esi - push %edi - mov 8+4(%esp),%esi /* 1st arg is prefix string */ - mov 8+8(%esp),%edi /* 2nd arg is main string */ -1: lodsb - test %al,%al - jz 2f - scasb - je 1b - sbb %eax,%eax - or $1,%al - jmp 3f -2: xor %eax,%eax -3: pop %edi - pop %esi - ret - -.Lstrlen: - push %ecx - push %esi - push %edi - xor %eax,%eax - xor %ecx,%ecx - not %ecx - mov 12+4(%esp),%edi - repne scasb - not %ecx - dec %ecx - mov %ecx,%eax - pop %edi - pop %esi - pop %ecx - ret - -.Lfind_option: - mov 4(%esp),%eax - dec %eax - push %ebx -1: pushl 4+8(%esp) - inc %eax - push %eax - call .Lstrstr - add $8,%esp - test %eax,%eax - jz 3f - cmp %eax,4+4(%esp) - je 2f - cmpb $' ',-1(%eax) - jne 1b -2: mov %eax,%ebx - pushl 4+8(%esp) - call .Lstrlen - add $4,%esp - xadd %eax,%ebx - /* NUL check (as $'\0' == 0x30 in GAS) */ - cmpb $0,(%ebx) - je 3f - cmpb $' ',(%ebx) - je 3f - cmpb $'=',(%ebx) - jne 1b -3: pop %ebx - ret - -cmdline_parse_early: - pusha - - /* Bail if there is no command line to parse. */ - mov sym_phys(multiboot_ptr),%ebx - mov MB_flags(%ebx),%eax - test $4,%al - jz .Lcmdline_exit - mov MB_cmdline(%ebx),%eax - test %eax,%eax - jz .Lcmdline_exit - - /* Check for 'no-real-mode' command-line option. */ - pushl $sym_phys(.Lno_rm_opt) - pushl MB_cmdline(%ebx) - call .Lfind_option - test %eax,%eax - setnz %al - or %al,sym_phys(skip_realmode) - - /* Check for 'tboot=' command-line option. */ - movl $sym_phys(.Ltboot_opt),4(%esp) - call .Lfind_option - test %eax,%eax - setnz %al - or %al,sym_phys(skip_realmode) /* tboot= implies no-real-mode */ - -.Lparse_edd: - /* Check for 'edd=' command-line option. */ - movl $sym_phys(.Ledd_opt),4(%esp) - call .Lfind_option - test %eax,%eax - jz .Lparse_edid - cmpb $'=',3(%eax) - jne .Lparse_edid - add $4,%eax - movb $2,sym_phys(opt_edd) /* opt_edd=2: edd=off */ - cmpw $0x666f,(%eax) /* 0x666f == "of" */ - je .Lparse_edid - decb sym_phys(opt_edd) /* opt_edd=1: edd=skipmbr */ - cmpw $0x6b73,(%eax) /* 0x6b73 == "sk" */ - je .Lparse_edid - decb sym_phys(opt_edd) /* opt_edd=0: edd=on (default) */ - -.Lparse_edid: - /* Check for 'edid=' command-line option. */ - movl $sym_phys(.Ledid_opt),4(%esp) - call .Lfind_option - test %eax,%eax - jz .Lparse_vga - cmpb $'=',4(%eax) - jne .Lparse_vga - add $5,%eax - mov %eax,%ebx - push %ebx - pushl $sym_phys(.Ledid_force) - call .Lstr_prefix - add $8,%esp - movb $2,sym_phys(opt_edid) /* opt_edid=2: edid=force */ - test %eax,%eax - jz .Lparse_vga - push %ebx - pushl $sym_phys(.Ledid_no) - call .Lstr_prefix - add $8,%esp - decb sym_phys(opt_edid) /* opt_edid=1: edid=no */ - test %eax,%eax - jz .Lparse_vga - decb sym_phys(opt_edid) /* opt_edid=0: default */ - -.Lparse_vga: - /* Check for 'vga=' command-line option. */ - movl $sym_phys(.Lvga_opt),4(%esp) - call .Lfind_option - add $8,%esp - test %eax,%eax - jz .Lcmdline_exit - cmpb $'=',3(%eax) - jne .Lcmdline_exit - add $4,%eax - - /* Found the 'vga=' option. Default option is to display vga menu. */ - movw $ASK_VGA,sym_phys(boot_vid_mode) - - /* Check for 'vga=text-80x. */ - mov %eax,%ebx - push %ebx - pushl $sym_phys(.Lvga_text80) - call .Lstr_prefix - add $8,%esp - test %eax,%eax - jnz .Lparse_vga_gfx - - /* We have 'vga=text-80x'. */ - add $8,%ebx - push %ebx - call .Latoi - add $4,%esp - mov %ax,%bx - lea sym_phys(.Lvga_text_modes),%esi -1: lodsw - test %ax,%ax - jz .Lcmdline_exit - cmp %ax,%bx - lodsw - jne 1b - mov %ax,sym_phys(boot_vid_mode) - jmp .Lcmdline_exit - -.Lparse_vga_gfx: - /* Check for 'vga=gfx-xx'. */ - push %ebx - pushl $sym_phys(.Lvga_gfx) - call .Lstr_prefix - add $8,%esp - test %eax,%eax - jnz .Lparse_vga_mode - - /* We have 'vga=gfx-xx'. */ - /* skip 'gfx-' */ - add $4,%ebx - /* parse */ - push %ebx - call .Latoi - pop %esi - mov %ax,sym_phys(vesa_size)+0 - /* skip 'x' */ - lodsb - cmpb $'x',%al - jne .Lcmdline_exit - /* parse */ - push %esi - call .Latoi - pop %esi - mov %ax,sym_phys(vesa_size)+2 - /* skip 'x' */ - lodsb - cmpb $'x',%al - jne .Lcmdline_exit - /* parse */ - push %esi - call .Latoi - pop %esi - mov %ax,sym_phys(vesa_size)+4 - /* commit to vesa mode */ - movw $VIDEO_VESA_BY_SIZE,sym_phys(boot_vid_mode) - jmp .Lcmdline_exit - -.Lparse_vga_mode: - /* Check for 'vga=mode-'. */ - push %ebx - pushl $sym_phys(.Lvga_mode) - call .Lstr_prefix - add $8,%esp - test %eax,%eax - jnz .Lparse_vga_current - - /* We have 'vga=mode-'. */ - add $5,%ebx - push %ebx - call .Latoi - add $4,%esp - mov %ax,sym_phys(boot_vid_mode) - jmp .Lcmdline_exit - -.Lparse_vga_current: - /* Check for 'vga=current'. */ - push %ebx - pushl $sym_phys(.Lvga_current) - call .Lstr_prefix - add $8,%esp - test %eax,%eax - jnz .Lcmdline_exit - - /* We have 'vga=current'. */ - movw $VIDEO_CURRENT_MODE,sym_phys(boot_vid_mode) - -.Lcmdline_exit: - popa - ret - - .pushsection .init.rodata, "a", @progbits - -.Lvga_text_modes: /* rows, mode_number */ - .word 25,VIDEO_80x25 - .word 50,VIDEO_80x50 - .word 43,VIDEO_80x43 - .word 28,VIDEO_80x28 - .word 30,VIDEO_80x30 - .word 34,VIDEO_80x34 - .word 60,VIDEO_80x60 - .word 0 - -.Lvga_opt: - .asciz "vga" -.Lvga_text80: - .asciz "text-80x" -.Lvga_gfx: - .asciz "gfx-" -.Lvga_mode: - .asciz "mode-" -.Lvga_current: - .asciz "current" -.Lno_rm_opt: - .asciz "no-real-mode" -.Ltboot_opt: - .asciz "tboot" -.Ledid_opt: - .asciz "edid" -.Ledid_force: - .asciz "force" -.Ledid_no: - .asciz "no" -.Ledd_opt: - .asciz "edd" - - .popsection diff --git a/xen/arch/x86/boot/cmdline.c b/xen/arch/x86/boot/cmdline.c new file mode 100644 index 0000000..a624fa9 --- /dev/null +++ b/xen/arch/x86/boot/cmdline.c @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved. + * Daniel Kiper + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + * strlen(), strncmp(), strspn() and strcspn() were copied from + * Linux kernel source (linux/lib/string.c). + * + * max() was copied from xen/xen/include/xen/kernel.h. + */ + +/* + * This entry point is entered from xen/arch/x86/boot/head.S with: + * - 0x4(%esp) = &cmdline, + * - 0x8(%esp) = &early_boot_opts. + */ +asm ( + " .text \n" + " .globl _start \n" + "_start: \n" + " jmp cmdline_parse_early \n" + ); + +#include "video.h" + +#define NULL ((void *)0) + +/* + * Space and TAB are obvious delimiters. However, I am + * adding "\n" and "\r" here too. Just in case when + * crazy bootloader/user put them somewhere. + */ +#define DELIM_CHARS " \n\r\t" +#define DELIM_CHARS_COMMA DELIM_CHARS "," + +#define __packed __attribute__((__packed__)) + +#define max(x,y) ({ \ + const typeof(x) _x = (x); \ + const typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x > _y ? _x : _y; }) + +#define tolower(c) ((c) | 0x20) + +/* + * Compiler is not able to optimize regular strlen() + * if argument is well known string during build. + * Hence, introduce optimized strlen_opt(). + */ +#define strlen_opt(s) (sizeof(s) - 1) + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int size_t; + +#define U16_MAX ((u16)(~0U)) + +/* Keep in sync with trampoline.S:early_boot_opts label! */ +typedef struct __packed { + u8 skip_realmode; + u8 opt_edd; + u8 opt_edid; + u16 boot_vid_mode; + u16 vesa_width; + u16 vesa_height; + u16 vesa_depth; +} early_boot_opts_t; + +static size_t strlen(const char *s) +{ + const char *sc; + + for ( sc = s; *sc != '\0'; ++sc ) + /* nothing */; + return sc - s; +} + +static int strncmp(const char *cs, const char *ct, size_t count) +{ + unsigned char c1, c2; + + while ( count ) + { + c1 = *cs++; + c2 = *ct++; + if ( c1 != c2 ) + return c1 < c2 ? -1 : 1; + if ( !c1 ) + break; + count--; + } + return 0; +} + +static size_t strspn(const char *s, const char *accept) +{ + const char *p; + const char *a; + size_t count = 0; + + for ( p = s; *p != '\0'; ++p ) + { + for ( a = accept; *a != '\0'; ++a ) + { + if ( *p == *a ) + break; + } + if ( *a == '\0' ) + return count; + ++count; + } + return count; +} + +static size_t strcspn(const char *s, const char *reject) +{ + const char *p; + const char *r; + size_t count = 0; + + for ( p = s; *p != '\0'; ++p ) + { + for ( r = reject; *r != '\0'; ++r ) + { + if ( *p == *r ) + return count; + } + ++count; + } + return count; +} + +static int strtoi(const char *s, const char *stop, const char **next) +{ + int base = 10, i, ores = 0, res = 0; + + if ( *s == '0' ) + base = (tolower(*++s) == 'x') ? (++s, 16) : 8; + + for ( ; *s != '\0'; ++s ) + { + for ( i = 0; stop && stop[i] != '\0'; ++i ) + if ( *s == stop[i] ) + goto out; + + if ( *s < '0' || (*s > '7' && base == 8) ) + { + res = -1; + goto out; + } + + if ( *s > '9' && (base != 16 || tolower(*s) < 'a' || tolower(*s) > 'f') ) + { + res = -1; + goto out; + } + + res *= base; + res += (tolower(*s) >= 'a') ? (tolower(*s) - 'a' + 10) : (*s - '0'); + + if ( ores > res ) + { + res = -1; + goto out; + } + + ores = res; + } + + out: + if ( next ) + *next = s; + + return res; +} + +static int strmaxcmp(const char *cs, const char *ct, const char *delim_chars) +{ + return strncmp(cs, ct, max(strcspn(cs, delim_chars), strlen(ct))); +} + +static int strsubcmp(const char *cs, const char *ct) +{ + return strncmp(cs, ct, strlen(ct)); +} + +static const char *find_opt(const char *cmdline, const char *opt, int arg) +{ + size_t lc, lo; + + lo = strlen(opt); + + for ( ; ; ) + { + cmdline += strspn(cmdline, DELIM_CHARS); + + if ( *cmdline == '\0' ) + return NULL; + + if ( !strmaxcmp(cmdline, "--", DELIM_CHARS) ) + return NULL; + + lc = strcspn(cmdline, DELIM_CHARS); + + if ( !strncmp(cmdline, opt, arg ? lo : max(lc, lo)) ) + return cmdline + lo; + + cmdline += lc; + } +} + +static u8 skip_realmode(const char *cmdline) +{ + return !!find_opt(cmdline, "no-real-mode", 0) || !!find_opt(cmdline, "tboot=", 1); +} + +static u8 edd_parse(const char *cmdline) +{ + const char *c; + + c = find_opt(cmdline, "edd=", 1); + + if ( !c ) + return 0; + + if ( !strmaxcmp(c, "off", DELIM_CHARS) ) + return 2; + + return !strmaxcmp(c, "skipmbr", DELIM_CHARS); +} + +static u8 edid_parse(const char *cmdline) +{ + const char *c; + + c = find_opt(cmdline, "edid=", 1); + + if ( !c ) + return 0; + + if ( !strmaxcmp(c, "force", DELIM_CHARS) ) + return 2; + + return !strmaxcmp(c, "no", DELIM_CHARS); +} + +static u16 rows2vmode(int rows) +{ + switch ( rows ) + { + case 25: + return VIDEO_80x25; + + case 28: + return VIDEO_80x28; + + case 30: + return VIDEO_80x30; + + case 34: + return VIDEO_80x34; + + case 43: + return VIDEO_80x43; + + case 50: + return VIDEO_80x50; + + case 60: + return VIDEO_80x60; + + default: + return ASK_VGA; + } +} + +static void vga_parse(const char *cmdline, early_boot_opts_t *ebo) +{ + const char *c; + int tmp; + + c = find_opt(cmdline, "vga=", 1); + + if ( !c ) + return; + + ebo->boot_vid_mode = ASK_VGA; + + if ( !strmaxcmp(c, "current", DELIM_CHARS_COMMA) ) + ebo->boot_vid_mode = VIDEO_CURRENT_MODE; + else if ( !strsubcmp(c, "text-80x") ) + { + c += strlen_opt("text-80x"); + ebo->boot_vid_mode = rows2vmode(strtoi(c, DELIM_CHARS_COMMA, NULL)); + } + else if ( !strsubcmp(c, "gfx-") ) + { + tmp = strtoi(c + strlen_opt("gfx-"), "x", &c); + + if ( tmp < 0 || tmp > U16_MAX ) + return; + + ebo->vesa_width = tmp; + + /* + * Increment c outside of strtoi() because otherwise some + * compiler may complain with following message: + * warning: operation on ā€˜cā€™ may be undefined. + */ + ++c; + tmp = strtoi(c, "x", &c); + + if ( tmp < 0 || tmp > U16_MAX ) + return; + + ebo->vesa_height = tmp; + + tmp = strtoi(++c, DELIM_CHARS_COMMA, NULL); + + if ( tmp < 0 || tmp > U16_MAX ) + return; + + ebo->vesa_depth = tmp; + + ebo->boot_vid_mode = VIDEO_VESA_BY_SIZE; + } + else if ( !strsubcmp(c, "mode-") ) + { + tmp = strtoi(c + strlen_opt("mode-"), DELIM_CHARS_COMMA, NULL); + + if ( tmp < 0 || tmp > U16_MAX ) + return; + + ebo->boot_vid_mode = tmp; + } +} + +void cmdline_parse_early(const char *cmdline, early_boot_opts_t *ebo) +{ + ebo->skip_realmode = skip_realmode(cmdline); + ebo->opt_edd = edd_parse(cmdline); + ebo->opt_edid = edid_parse(cmdline); + vga_parse(cmdline, ebo); +} diff --git a/xen/arch/x86/boot/edd.S b/xen/arch/x86/boot/edd.S index 5c80da6..73371f9 100644 --- a/xen/arch/x86/boot/edd.S +++ b/xen/arch/x86/boot/edd.S @@ -142,9 +142,6 @@ edd_next: edd_done: ret -opt_edd: - .byte 0 # edd=on/off/skipmbr - GLOBAL(boot_edd_info_nr) .byte 0 GLOBAL(boot_mbr_signature_nr) diff --git a/xen/arch/x86/boot/head.S b/xen/arch/x86/boot/head.S index efb0614..964851b 100644 --- a/xen/arch/x86/boot/head.S +++ b/xen/arch/x86/boot/head.S @@ -436,8 +436,24 @@ trampoline_setup: cmp $sym_phys(__trampoline_seg_stop),%edi jb 1b + /* Do not parse command line on EFI platform here. */ + cmpb $1,sym_phys(skip_realmode) + je 1f + + /* Bail if there is no command line to parse. */ + mov sym_phys(multiboot_ptr),%ebx + testl $MBI_CMDLINE,MB_flags(%ebx) + jz 1f + + cmpl $0,MB_cmdline(%ebx) + jz 1f + + pushl $sym_phys(early_boot_opts) + pushl MB_cmdline(%ebx) call cmdline_parse_early + add $8,%esp /* Remove cmdline_parse_early() args from stack. */ +1: /* Switch to low-memory stack. */ mov sym_phys(trampoline_phys),%edi lea 0x10000(%edi),%esp @@ -453,6 +469,7 @@ trampoline_setup: /* Jump into the relocated trampoline. */ lret +cmdline_parse_early: #include "cmdline.S" reloc: diff --git a/xen/arch/x86/boot/trampoline.S b/xen/arch/x86/boot/trampoline.S index b013614..8a32728 100644 --- a/xen/arch/x86/boot/trampoline.S +++ b/xen/arch/x86/boot/trampoline.S @@ -220,8 +220,20 @@ trampoline_boot_cpu_entry: /* Jump to the common bootstrap entry point. */ jmp trampoline_protmode_entry +#include "video.h" + +/* Keep in sync with cmdline.c:early_boot_opts_t type! */ +early_boot_opts: skip_realmode: .byte 0 +opt_edd: + .byte 0 /* edd=on/off/skipmbr */ +opt_edid: + .byte 0 /* EDID parsing option (force/no/default). */ +GLOBAL(boot_vid_mode) + .word VIDEO_80x25 /* If we don't run at all, assume basic video mode 3 at 80x25. */ +vesa_size: + .word 0,0,0 /* width x depth x height */ GLOBAL(kbd_shift_flags) .byte 0 diff --git a/xen/arch/x86/boot/video.S b/xen/arch/x86/boot/video.S index b238bf3..335a51c 100644 --- a/xen/arch/x86/boot/video.S +++ b/xen/arch/x86/boot/video.S @@ -945,7 +945,6 @@ store_edid: #endif ret -opt_edid: .byte 0 # EDID parsing option (force/no/default) mt_end: .word 0 # End of video mode table if built edit_buf: .space 6 # Line editor buffer card_name: .word 0 # Pointer to adapter name @@ -991,11 +990,6 @@ name_bann: .asciz "Video adapter: " force_size: .word 0 # Use this size instead of the one in BIOS vars -vesa_size: .word 0,0,0 # width x depth x height - -/* If we don't run at all, assume basic video mode 3 at 80x25. */ -GLOBAL(boot_vid_mode) - .word VIDEO_80x25 GLOBAL(boot_vid_info) .byte 0, 0 /* orig_x, orig_y */ .byte 3 /* text mode 3 */