On Tue, Jan 28, 2014 at 8:30 AM, Uros Bizjak <ubiz...@gmail.com> wrote: > On Tue, Jan 28, 2014 at 5:01 PM, Uros Bizjak <ubiz...@gmail.com> wrote: >> On Mon, Jan 27, 2014 at 8:44 PM, H.J. Lu <hongjiu...@intel.com> wrote: >> >>> The .code16gcc directive was added to binutils back in 1999: >>> >>> --- >>> '.code16gcc' provides experimental support for generating 16-bit code >>> from gcc, and differs from '.code16' in that 'call', 'ret', 'enter', >>> 'leave', 'push', 'pop', 'pusha', 'popa', 'pushf', and 'popf' >>> instructions default to 32-bit size. This is so that the stack pointer >>> is manipulated in the same way over function calls, allowing access to >>> function parameters at the same stack offsets as in 32-bit mode. >>> '.code16gcc' also automatically adds address size prefixes where >>> necessary to use the 32-bit addressing modes that gcc generates. >>> --- >>> >>> It encodes 32-bit assembly instructions generated by GCC in 16-bit format >>> so that GCC can be used to generate 16-bit instructions. To do that, the >>> .code16gcc directive may be placed at the very beginning of the assembly >>> code. This patch adds -m16 to x86 backend by: >>> >>> 1. Add -m16 and make it mutually exclusive with -m32, -m64 and -mx32. >>> 2. Treat -m16 like -m32 so that --32 is passed to assembler. >>> 3. Output .code16gcc at the very beginning of the assembly code. >>> 4. Turn off 64-bit ISA when -m16 is used. >>> >>> Tested on Linux/x86 and Linux/x86-64. OK for trunk? >>> >>> Thanks. >>> >>> H.J. >>> --- >>> PR target/59672 >>> * config/i386/gnu-user64.h (SPEC_32): Add "m16|" to "m32". >>> (SPEC_X32): Likewise. >>> (SPEC_64): Likewise. >>> * config/i386/i386.c (ix86_option_override_internal): Turn off >>> OPTION_MASK_ISA_64BIT, OPTION_MASK_ABI_X32 and OPTION_MASK_ABI_64 >>> for TARGET_16BIT. >>> (x86_file_start): Output .code16gcc for TARGET_16BIT. >>> * config/i386/i386.h (TARGET_16BIT): New macro. >>> (TARGET_16BIT_P): Likewise. >>> * config/i386/i386.opt: Add m16. >>> * doc/invoke.texi: Document -m16. >> >> OK for mainline, needs OK from RMs for a backport. >> >> Please also add the entry to Changes.html, this is user-visible change. > > Oh, a short scan-asm testcase would be nice, too. >
scan-asm testcase doesn't do anything useful. The only difference in assembly code between -m16 and -m32 is the .code16gcc directive All magic is done in assembler. Here is a run-time test. It builds 16-bit image for BIOS and loads it into qemu-system-i386. OK to install? Thanks. -- H.J. --- PR target/59672 * gcc.target/i386/m16/Makefile: New file. * gcc.target/i386/m16/m16.exp: Likewise. * gcc.target/i386/m16/include16/string.h: Likewise. * gcc.target/i386/m16/include16/sys16.h: Likewise. * gcc.target/i386/m16/lib16/conio.c: Likewise. * gcc.target/i386/m16/lib16/crt0.c: Likewise. * gcc.target/i386/m16/lib16/exit.c: Likewise. * gcc.target/i386/m16/lib16/strlen.c: Likewise. * gcc.target/i386/m16/run/run16.c: Likewise. * gcc.target/i386/m16/run/wrap.S: Likewise. * gcc.target/i386/m16/run/wwrap.S: Likewise. * gcc.target/i386/m16/test16/test1.c: Likewise.
From 67f20cece3a500c26ace8992d868bbaeec53e4a4 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" <hjl.to...@gmail.com> Date: Thu, 23 Jan 2014 06:51:14 -0800 Subject: [PATCH 2/2] Initial -m16 test PR target/59672 * gcc.target/i386/m16/Makefile: New file. * gcc.target/i386/m16/m16.exp: Likewise. * gcc.target/i386/m16/include16/string.h: Likewise. * gcc.target/i386/m16/include16/sys16.h: Likewise. * gcc.target/i386/m16/lib16/conio.c: Likewise. * gcc.target/i386/m16/lib16/crt0.c: Likewise. * gcc.target/i386/m16/lib16/exit.c: Likewise. * gcc.target/i386/m16/lib16/strlen.c: Likewise. * gcc.target/i386/m16/run/run16.c: Likewise. * gcc.target/i386/m16/run/wrap.S: Likewise. * gcc.target/i386/m16/run/wwrap.S: Likewise. * gcc.target/i386/m16/test16/test1.c: Likewise. --- gcc/ChangeLog.m16 | 19 ++ gcc/testsuite/gcc.target/i386/m16/Makefile | 89 ++++++ .../gcc.target/i386/m16/include16/string.h | 6 + .../gcc.target/i386/m16/include16/sys16.h | 24 ++ gcc/testsuite/gcc.target/i386/m16/lib16/conio.c | 19 ++ gcc/testsuite/gcc.target/i386/m16/lib16/crt0.c | 9 + gcc/testsuite/gcc.target/i386/m16/lib16/exit.c | 9 + gcc/testsuite/gcc.target/i386/m16/lib16/strlen.c | 11 + gcc/testsuite/gcc.target/i386/m16/m16.exp | 55 ++++ gcc/testsuite/gcc.target/i386/m16/run/run16.c | 312 +++++++++++++++++++++ gcc/testsuite/gcc.target/i386/m16/run/wrap.S | 180 ++++++++++++ gcc/testsuite/gcc.target/i386/m16/run/wwrap.S | 13 + gcc/testsuite/gcc.target/i386/m16/test16/test1.c | 7 + 13 files changed, 753 insertions(+) create mode 100644 gcc/testsuite/gcc.target/i386/m16/Makefile create mode 100644 gcc/testsuite/gcc.target/i386/m16/include16/string.h create mode 100644 gcc/testsuite/gcc.target/i386/m16/include16/sys16.h create mode 100644 gcc/testsuite/gcc.target/i386/m16/lib16/conio.c create mode 100644 gcc/testsuite/gcc.target/i386/m16/lib16/crt0.c create mode 100644 gcc/testsuite/gcc.target/i386/m16/lib16/exit.c create mode 100644 gcc/testsuite/gcc.target/i386/m16/lib16/strlen.c create mode 100644 gcc/testsuite/gcc.target/i386/m16/m16.exp create mode 100644 gcc/testsuite/gcc.target/i386/m16/run/run16.c create mode 100644 gcc/testsuite/gcc.target/i386/m16/run/wrap.S create mode 100644 gcc/testsuite/gcc.target/i386/m16/run/wwrap.S create mode 100644 gcc/testsuite/gcc.target/i386/m16/test16/test1.c diff --git a/gcc/ChangeLog.m16 b/gcc/ChangeLog.m16 index 05424d9..feb1891 100644 --- a/gcc/ChangeLog.m16 +++ b/gcc/ChangeLog.m16 @@ -1,3 +1,22 @@ +gcc/testsuite/ + +2014-01-23 H. Peter Anvin <h...@zytor.com> + H.J. Lu <hongjiu...@intel.com> + + PR target/59672 + * gcc.target/i386/m16/Makefile: New file. + * gcc.target/i386/m16/m16.exp: Likewise. + * gcc.target/i386/m16/include16/string.h: Likewise. + * gcc.target/i386/m16/include16/sys16.h: Likewise. + * gcc.target/i386/m16/lib16/conio.c: Likewise. + * gcc.target/i386/m16/lib16/crt0.c: Likewise. + * gcc.target/i386/m16/lib16/exit.c: Likewise. + * gcc.target/i386/m16/lib16/strlen.c: Likewise. + * gcc.target/i386/m16/run/run16.c: Likewise. + * gcc.target/i386/m16/run/wrap.S: Likewise. + * gcc.target/i386/m16/run/wwrap.S: Likewise. + * gcc.target/i386/m16/test16/test1.c: Likewise. + gcc/ 2014-01-23 H.J. Lu <hongjiu...@intel.com> diff --git a/gcc/testsuite/gcc.target/i386/m16/Makefile b/gcc/testsuite/gcc.target/i386/m16/Makefile new file mode 100644 index 0000000..c805701 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/m16/Makefile @@ -0,0 +1,89 @@ +CC = gcc +LD = ld +AR = ar +OBJCOPY = objcopy + +GCCWARN = -Wall -Wstrict-prototypes +CFLAGS = -g -m32 -O2 -fno-strict-aliasing $(GCCWARN) +SFLAGS = $(CFLAGS) -D__ASSEMBLY__ +LDFLAGS = $(CFLAGS) +M16 = -m16 + +SRC-DIR = . +VPATH = $(SRC-DIR) +X16FLAGS = -g $(M16) -D__SYS16__ -I $(SRC-DIR)/include16 +S16FLAGS = $(X16FLAGS) -D__ASSEMBLY__ +C16OPTFLAGS = -Os +C16FLAGS = $(X16FLAGS) $(GCCWARN) -march=i386 -mregparm=3 \ + $(C16OPTFLAGS) -ffreestanding \ + -fno-stack-protector -mpreferred-stack-boundary=2 \ + -fno-pic + +LD16FLAGS = -m elf_i386 --section-start=.text=0x1000 +LDWRAPFLAGS = -m elf_i386 --section-start=.text=0x8000 + +LIB16S = +LIB16C = conio.c crt0.c exit.c strlen.c +LIB16C := $(addprefix lib16/,$(LIB16C)) +LIB16O = $(LIB16C:.c=.o) $(LIB16S:.S=.o) + +TEST1O = test16/test1.o +TEST1ELF = $(TEST1O:.o=.elf) + +all : run16 $(TEST1ELF) + ./run16 $(TEST1ELF) + +lib16/%.o: lib16/%.S + mkdir -p lib16 + $(CC) $(S16FLAGS) -c -o $@ $< + +lib16/%.o: lib16/%.c + mkdir -p lib16 + $(CC) $(C16FLAGS) -c -o $@ $< + +lib16/lib16.a: $(LIB16O) + mkdir -p $(@D) + rm -f $@ + $(AR) cq $@ $^ + +test16/%.o: test16/%.S + mkdir -p $(@D) + $(CC) $(S16FLAGS) -c -o $@ $< + +test16/%.o: test16/%.c + mkdir -p $(@D) + $(CC) $(C16FLAGS) -c -o $@ $< + +test16/%.elf: test16/%.o lib16/lib16.a + mkdir -p $(@D) + $(LD) $(LD16FLAGS) -o $@ $^ + +run/wrap.elf: run/wrap.o + mkdir -p $(@D) + $(LD) $(LDWRAPFLAGS) -o $@ $^ + +run/wrap.bin: run/wrap.elf + mkdir -p $(@D) + $(OBJCOPY) -O binary $< $@ + +run/wwrap.o: run/wwrap.S run/wrap.bin + +run/%.o: run/%.S + mkdir -p $(@D) + $(CC) $(SFLAGS) -c -o $@ $< + +run/%.o: run/%.c + mkdir -p $(@D) + $(CC) $(CFLAGS) -c -o $@ $< + +run16: run/run16.o run/wwrap.o + mkdir -p $(@D) + $(CC) $(LDFLAGS) -o $@ $^ + +clean: + rm -f run16 *.o lib16/*.o lib16/*.a + rm -f test16/*.o test16/*.elf test16/*.bin + rm -f run/*.o run/*.elf run/*.bin + +spotless: clean + rm -f *~ */*~ diff --git a/gcc/testsuite/gcc.target/i386/m16/include16/string.h b/gcc/testsuite/gcc.target/i386/m16/include16/string.h new file mode 100644 index 0000000..ec50591 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/m16/include16/string.h @@ -0,0 +1,6 @@ +#ifndef _STRING_H +#define _STRING_H + +int strlen(const char *); + +#endif /* _STRING_H */ diff --git a/gcc/testsuite/gcc.target/i386/m16/include16/sys16.h b/gcc/testsuite/gcc.target/i386/m16/include16/sys16.h new file mode 100644 index 0000000..1073009 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/m16/include16/sys16.h @@ -0,0 +1,24 @@ +#ifndef SYS16_H +#define SYS16_H + +#ifdef __SYS16__ +# define _PTR16(x) x +#else +# define _PTR16(x) unsigned int +#endif + +struct system_struct { + _PTR16(void *) entrypoint; + int argc; + _PTR16(char **)argv; +}; + +#undef _PTR16 + +#define SYS_STRUCT_ADDR 0xf000 + +#ifdef __SYS16__ +# define SYS ((struct system_struct *)SYS_STRUCT_ADDR) +#endif + +#endif /* SYS16_H */ diff --git a/gcc/testsuite/gcc.target/i386/m16/lib16/conio.c b/gcc/testsuite/gcc.target/i386/m16/lib16/conio.c new file mode 100644 index 0000000..5d5871a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/m16/lib16/conio.c @@ -0,0 +1,19 @@ +#include <string.h> +#include <sys16.h> + +int write(int fd, const void *buf, unsigned int count) +{ + const char *p = buf; + unsigned int c = count; + + while (c--) + asm volatile("outb %0,$0xe9" : : "a" (*p++)); + + return count; +} + +void puts(const char *s) +{ + /* XXX: should loop over this */ + write(1, s, strlen(s)); +} diff --git a/gcc/testsuite/gcc.target/i386/m16/lib16/crt0.c b/gcc/testsuite/gcc.target/i386/m16/lib16/crt0.c new file mode 100644 index 0000000..34f6b36 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/m16/lib16/crt0.c @@ -0,0 +1,9 @@ +#include <sys16.h> + +extern int main(int, char **); +extern void exit(int); + +void _start(void) +{ + exit(main(SYS->argc, SYS->argv)); +} diff --git a/gcc/testsuite/gcc.target/i386/m16/lib16/exit.c b/gcc/testsuite/gcc.target/i386/m16/lib16/exit.c new file mode 100644 index 0000000..991bd23 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/m16/lib16/exit.c @@ -0,0 +1,9 @@ +void exit(int c) +{ + unsigned char x = c ? 'F' : 'S'; + unsigned short port = 0x501; + + asm volatile("outb %0,%1" : : "a" (x), "d" (port)); + for(;;) + asm volatile("hlt"); +} diff --git a/gcc/testsuite/gcc.target/i386/m16/lib16/strlen.c b/gcc/testsuite/gcc.target/i386/m16/lib16/strlen.c new file mode 100644 index 0000000..7d6dd15 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/m16/lib16/strlen.c @@ -0,0 +1,11 @@ +#include <string.h> + +int strlen(const char *c) +{ + const char *c0 = c; + + while (*c) + c++; + + return c - c0; +} diff --git a/gcc/testsuite/gcc.target/i386/m16/m16.exp b/gcc/testsuite/gcc.target/i386/m16/m16.exp new file mode 100644 index 0000000..a67c827 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/m16/m16.exp @@ -0,0 +1,55 @@ +# Expect script for -m16 tests +# Copyright (C) 2014 Free Software Foundation, Inc. + +# 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 3 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 GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# Load support procs. +load_lib c-torture.exp +load_lib target-supports.exp +load_lib torture-options.exp + +# Exit immediately if this isn't a native Linux/x86 target. +if { ![isnative] + || ![check_effective_target_ia32] + || ![istarget *-*-linux*] + || [istarget *-*-linux*aout*] + || [istarget *-*-linux*oldld*] } { + return +} + +# Check if qemu-system-i386 exists. +set status [catch "exec qemu-system-i386 -h" exec_output] +if { $status != 0 } { + return +} + +catch "exec mkdir -p m16" status +set status [catch "exec cp -L $srcdir/$subdir/Makefile m16" exec_output] +if { $status != 0 } { + unresolved "-m16" + send_log "$exec_output\n" + return +} + +foreach opt $C_TORTURE_OPTIONS { + set status [catch "exec make -C m16 clean" exec_output] + set status [catch "exec make -C m16 SRC-DIR=$srcdir/$subdir \"CC=$GCC_UNDER_TEST\" \"C16OPTFLAGS=$opt\"" exec_output] + send_log "$exec_output\n" + if { $status != 0 } { + fail "-m16 $opt" + } else { + pass "-m16 $opt" + } +} diff --git a/gcc/testsuite/gcc.target/i386/m16/run/run16.c b/gcc/testsuite/gcc.target/i386/m16/run/run16.c new file mode 100644 index 0000000..a81c84a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/m16/run/run16.c @@ -0,0 +1,312 @@ +/* + * Wrapper to run a 16-bit raw binary as a "BIOS image" under Qemu + */ + +#define _GNU_SOURCE +#include <elf.h> +#include <errno.h> +#include <fcntl.h> +#include <paths.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include "../include16/sys16.h" + +/* + * The program (toybox) is loaded at 0xe0000 and then copied down to + * 0x10000 to be in "RAM"; the wrapper_data is loaded at 0xf0000 and + * contains anything needed to set up the early execution environment. + */ +#define TOYBOX_SIZE 65536 +#define WRAPPER_SIZE 65536 + +static unsigned char *toybox, *wrapper_data; +static int toyprot[TOYBOX_SIZE/4096]; +extern const unsigned char wrapper[]; +extern const unsigned int wrapper_len; + +#define ALIGN_UP(x,y) (((x) + (y) - 1) & ~((y) - 1)) + +static void init_page_tables(void) +{ + int i; + uint64_t *page_tables = (uint64_t *)(wrapper_data + 0x2000); + + /* Map 256 pages = 1MiB */ + for (i = 0; i < 1024/4; i++) { + /* Page present, RWX, system */ + page_tables[i] = (i << 12) | 0x063; + } + + /* Map 64-128K as user pages with appropriate permissions */ + for (i = 64/4; i < 128/4; i++) { + int tp = toyprot[i-64/4]; + page_tables[i] = (i << 12) | 0x064 + | ((tp & PF_X) ? 0 : (UINT64_C(1) << 63)) + | ((tp & PF_W) ? 2 : 0) + | ((tp & (PF_X|PF_W|PF_R)) ? 1 : 0); + } + + /* Set up PDPTR */ + *(uint64_t *)(wrapper_data + 0x0000) = 0xf1000 | 1; + + /* Set up PDE */ + *(uint64_t *)(wrapper_data + 0x1000) = 0xf2000 | 0x027; +} + +static void init_reset_vector(void) +{ + /* jmp far 0xf000:0x8000 */ + memcpy(wrapper_data + 0xfff0, "\xea\x00\x80\x00\xf0", 5); +} + +static void init_wrapper(void) +{ + /* Fixed wrapper data at 0xf000:0x8000 */ + memcpy(wrapper_data + 0x8000, wrapper, wrapper_len); + + init_page_tables(); + + init_reset_vector(); +} + +static int load_elf(const char *file, uint32_t *start) +{ + int fd; + struct stat st; + const char *fp; /* File data pointer */ + const Elf32_Ehdr *eh; + const Elf32_Phdr *ph; + int rv = -1; + int i; + + fd = open(file, O_RDONLY); + if (fd < 0 || fstat(fd, &st)) + goto bail; + + fp = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (fp == MAP_FAILED) + goto bail; + + errno = ENOEXEC; /* If no other error... */ + + /* Must be long enough */ + if (st.st_size < sizeof(Elf32_Ehdr)) + goto bail; + + eh = (const Elf32_Ehdr *)fp; + + /* Must be ELF, 32-bit, littleendian, version 1 */ + if (memcmp(eh->e_ident, "\x7f" "ELF\1\1\1", 6)) + goto bail; + + if (eh->e_machine != EM_386) + goto bail; + + if (eh->e_version != EV_CURRENT) + goto bail; + + if (eh->e_ehsize < sizeof(Elf32_Ehdr) || eh->e_ehsize >= st.st_size) + goto bail; + + if (eh->e_phentsize < sizeof(Elf32_Phdr)) + goto bail; + + if (!eh->e_phnum) + goto bail; + + if (eh->e_phoff + eh->e_phentsize * eh->e_phnum > st.st_size) + goto bail; + + if (eh->e_entry > TOYBOX_SIZE) + goto bail; + + *start = eh->e_entry; + + ph = (const Elf32_Phdr *)(fp + eh->e_phoff); + + for (i = 0; i < eh->e_phnum; i++) { + uint32_t addr = ph->p_paddr; + uint32_t msize = ph->p_memsz; + uint32_t dsize = ph->p_filesz; + int page, flags; + + ph = (const Elf32_Phdr *)((const char *)ph + + i*eh->e_phentsize); + + if (msize && (ph->p_type == PT_LOAD || + ph->p_type == PT_PHDR)) { + /* + * This loads at p_paddr, which is arguably + * the correct semantics (LMA). The SysV spec + * says that SysV loads at p_vaddr (and thus + * Linux does, too); that is, however, a major + * brainfuckage in the spec. + */ + if (msize < dsize) + dsize = msize; + + if (addr >= TOYBOX_SIZE || + addr + msize > TOYBOX_SIZE) + goto bail; + + if (dsize) { + if (ph->p_offset >= st.st_size || + ph->p_offset + dsize > st.st_size) + goto bail; + memcpy(toybox + addr, fp + ph->p_offset, + dsize); + } + + memset(toybox + addr + dsize, 0, msize - dsize); + + flags = ph->p_flags & (PF_X|PF_W|PF_R); + for (page = addr & ~0xfff; page < addr + msize; + page += 4096) + toyprot[page >> 12] |= flags; + } + } + + rv = 0; /* Success! */ + +bail: + if (fd >= 0) + close(fd); + return rv; +} + +static void build_env(const char *file, char **argv) +{ + uint32_t start; + struct system_struct *SYS; + char **argp; + uint32_t argptr, argstr; + + /* Read the input file */ + if (load_elf(file, &start)) + goto barf; + + /* Set up the system structure */ + SYS = (struct system_struct *)(toybox + SYS_STRUCT_ADDR); + SYS->entrypoint = start; + for (argp = argv; *argp; argp++) + SYS->argc++; + + argptr = ALIGN_UP(SYS_STRUCT_ADDR + sizeof(struct system_struct), 4); + argstr = argptr + (SYS->argc + 1)*sizeof(uint32_t); + + SYS->argv = argptr; + + for (argp = argv; *argp; argp++) { + int len = strlen(*argp)+1; + + if (argstr + len >= TOYBOX_SIZE) { + fprintf(stderr, "run16: %s: command line too long\n", + file); + exit(127); + } + + *(uint32_t *)(toybox + argptr) = argstr; + argptr += sizeof(uint32_t); + memcpy(toybox + argstr, *argp, len); + argstr += len; + } + + /* Set up page protection */ + toyprot[0xE] |= PF_R | PF_W; /* Stack page */ + toyprot[0xF] |= PF_R; /* System page */ + + init_wrapper(); + return; + +barf: + fprintf(stderr, "run16: %s: %s\n", file, strerror(errno)); + exit(127); +} + +static int run(const char *qemu, const char *file, char **argv) +{ + const char *tmpdir, *et; + char *filename; + int fd, status, err; + pid_t p; + + tmpdir = getenv("TMPDIR"); + if (!tmpdir) + tmpdir = _PATH_TMP; + + et = strchr(tmpdir, '\0'); + if (asprintf(&filename, "%s%srun16.tmp.XXXXXX", tmpdir, + (et == tmpdir || et[-1] == '/') ? "" : "/") < 0) + goto barf_no_rm; + fd = mkstemp(filename); + if (fd < 0) + goto barf_no_rm; + + if (ftruncate(fd, TOYBOX_SIZE + WRAPPER_SIZE)) + goto barf; + + toybox = mmap(NULL, TOYBOX_SIZE + WRAPPER_SIZE, PROT_READ|PROT_WRITE, + MAP_SHARED, fd, 0); + if (toybox == MAP_FAILED) + goto barf; + + wrapper_data = toybox + TOYBOX_SIZE; + + build_env(file, argv); + + if (munmap(toybox, TOYBOX_SIZE + WRAPPER_SIZE)) + goto barf; + if (close(fd)) + goto barf; + + fflush(NULL); + + p = fork(); + if (p < 0) + goto barf; + + if (p == 0) { + execlp(qemu, qemu, "-cpu", "qemu32,+xd", + "-nodefaults", "-nodefconfig", + "-m", "1", "-display", "none", "-vga", "none", + "-debugcon", "stdio", "-device", "isa-debug-exit", + "-bios", filename, (char *)NULL); + _exit(127); + } + + while (waitpid(p, &status, 0) != p) + ; + + unlink(filename); + + return (WIFEXITED(status) && WEXITSTATUS(status) == (('S' << 1) | 1) + ? 0 : 1); + +barf: + err = errno; + unlink(filename); + errno = err; +barf_no_rm: + fprintf(stderr, "run16: %s: %s\n", file, strerror(errno)); + exit(127); +} + +int main(int argc, char *argv[]) +{ + const char *qemu = "qemu-system-i386"; + + if (argc < 2) { + fprintf(stderr, "Usage: %s filename [args...]\n", argv[0]); + return 127; + } + + return run(qemu, argv[1], argv+1); +} diff --git a/gcc/testsuite/gcc.target/i386/m16/run/wrap.S b/gcc/testsuite/gcc.target/i386/m16/run/wrap.S new file mode 100644 index 0000000..b9ba1af --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/m16/run/wrap.S @@ -0,0 +1,180 @@ +/* + * Code wrapper: set up a 16-bit protected mode environment with + * paging enabled, so we can catch permission violations. + * + * This will be combined with the target program and fed as a single + * 128K binary "BIOS" image to Qemu, which will load it at 0xe0000. + * + * The first 64K is the actual program, then immediately follows + * PAE page tables set up so the low 1M is identity-mapped, with + * 64K-128K as user mode with appropriate permissions and the balance + * as RWX supervisor. + * + * This chunk is then loaded at 32K, and finally the reset vector at + * -16 bytes with a jump to f000:8000. + */ + .code16 + .text + .globl _start +_start: + cld + + /* Copy the program code to 0x10000, in Qemu "RAM" */ + movw $0xe000,%ax + movw %ax,%ds + movw $0x1000,%ax + movw %ax,%es + movw $0x4000,%cx + rep; movsl + + movw %cs,%ax + movw %ax,%ds + xorw %ax,%ax + movw %ax,%ss + movl $0xfff0,%esp + movw %ax,%es + + /* Set up GDT at 0:0x1000, followed by TSS */ + movw $gdt_master,%si + movw $0x1000,%di + movw $(gdt_len + 104),%cx + shrw $2,%cx + rep; movsl + + lgdtl gdt_desc + lidtl idt_desc + + movl $0x30,%eax /* Enable PAE and PSE */ + movl %eax,%cr4 + + movl $0xc0000080,%ecx /* IA32_EFER */ + rdmsr + orl $(1 << 11),%eax /* Enable NX */ + wrmsr + + movl $0xf0000,%eax /* Page table base */ + movl %eax,%cr3 + + movw $0x10,%dx /* Data segment */ + movw $0x18,%cx /* Stack segment */ + movw $0x30,%bx /* TSS segment */ + xorw %si,%si /* Null selector */ + + movl $0x80010033,%eax + movl %eax,%cr0 + ljmpw $0x08,$1f +1: + movw %cx,%ss + movw %dx,%ds + movw %dx,%es + movw %si,%fs /* fs/gs should never be implicitly accessed */ + movw %si,%gs + ltr %bx + + movw $0x2b,%dx /* User data segment */ + pushw %dx /* User SS */ + pushw $0xf000 /* User SP */ + pushw $0x3002 /* User FLAGS (IOPL=3) */ + pushw $0x23 /* User CS */ + movw %dx,%ds + pushw 0xf000 /* sysseg:0xf000 holds the user IP */ + movw %dx,%es + iretw /* Go to user program */ + + .balign 16 +trap_handler: + movb $'T',%al /* T = trap */ + movw $0x501,%dx + outb %al,%dx + /* This should kill Qemu */ +die: + hlt + jmp die + + .section ".rodata","a" + .balign 16 +gdt_desc: + .word gdt_len + .long 0x1000 + .word 0 + +gdt_master: + .long 0,0 + + /* Segment 0x08: 16-bit system code segment (in ROM) */ + .word 0xffff /* Limit[15:0] */ + .long 0x0f0000 + 0x9b000000 /* Base[24:0] + code segment */ + .word 0x0000 /* Base[31:24] + 16-bit segment */ + + /* Segment 0x10: 16-bit system data segment (in ROM) */ + .word 0xffff /* Limit[15:0] */ + .long 0x0f0000 + 0x93000000 /* Base[24:0] + code segment */ + .word 0x0000 /* Base[31:24] + 16-bit segment */ + + /* Segment 0x18: 16-bit system stack segment (in low memory) */ + .word 0xffff /* Limit[15:0] */ + .long 0x000000 + 0x93000000 /* Base[24:0] + code segment */ + .word 0x0000 /* Base[31:24] + 16-bit segment */ + + /* Segment 0x23: 16-bit user code segment */ + .word 0xffff /* Limit[15:0] */ + .long 0x010000 + 0xfb000000 /* Base[24:0] + code segment */ + .word 0x0000 /* Base[31:24] + 16-bit segment */ + + /* Segment 0x2b: 16-bit user data segment */ + .word 0xffff /* Limit[15:0] */ + .long 0x010000 + 0xf3000000 /* Base[24:0] + code segment */ + .word 0x0000 /* Base[31:24] + 16-bit segment */ + + /* Segment 0x30: TSS */ + .word 104 /* Limit */ + .long (0x001000 + gdt_len) + 0x89000000 + /* Base[15:0] + available TSS */ + .word 0x0000 /* Base[31:24] + limit[19:16] */ + +gdt_len = . - gdt_master + + /* Must immediately follow the GDT */ +tss_master: + .long 0 /* Task link */ + .long 0 /* ESP0 */ + .long 0x18 /* SS0 */ + .long 0 /* ESP1 */ + .long 0 /* SS1 */ + .long 0 /* ESP2 */ + .long 0 /* SS2 */ + .long 0xf0000 /* CR3 */ + .long 0 /* EIP */ + .long 0 /* EFLAGS */ + .long 0 /* EAX */ + .long 0 /* ECX */ + .long 0 /* EDX */ + .long 0 /* EBX */ + .long 0 /* ESP */ + .long 0 /* EBP */ + .long 0 /* ESI */ + .long 0 /* EDI */ + .long 0 /* ES */ + .long 0 /* CS */ + .long 0 /* SS */ + .long 0 /* DS */ + .long 0 /* FS */ + .long 0 /* GS */ + .long 0 /* LDTR */ + .long 0xffff0000 /* T + IObase */ + +idt_desc: + .word idt_len + .long idt + 0xf0000 + .word 0 + + .balign 16 +idt: + .rept 256 + .word trap_handler /* Offset[15:0] */ + .word 0x08 /* Code segment */ + .word 0x8600 /* Interrupt gate, DPL 0 */ + .word 0 /* Offset[31:16] */ + .endr + +idt_len = . - idt diff --git a/gcc/testsuite/gcc.target/i386/m16/run/wwrap.S b/gcc/testsuite/gcc.target/i386/m16/run/wwrap.S new file mode 100644 index 0000000..3dfe5d6 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/m16/run/wwrap.S @@ -0,0 +1,13 @@ + .section ".rodata","a" + .globl wrapper +wrapper: + .incbin "run/wrap.bin" + .balign 16 + .size wrapper,.-wrapper + + .globl wrapper_len +wrapper_len: + .long .-wrapper + .size wrapper_len,.-wrapper_len + + .section .note.GNU-stack,"",@progbits diff --git a/gcc/testsuite/gcc.target/i386/m16/test16/test1.c b/gcc/testsuite/gcc.target/i386/m16/test16/test1.c new file mode 100644 index 0000000..b79e7be --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/m16/test16/test1.c @@ -0,0 +1,7 @@ +extern void puts(const char *); + +int main(void) +{ + puts("Hello, World!\n"); + return 0; +} -- 1.8.5.3