summaryrefslogtreecommitdiff
path: root/tests/multiboot
diff options
context:
space:
mode:
authorKevin Wolf <kwolf@redhat.com>2013-06-27 13:50:05 +0200
committerKevin Wolf <kwolf@redhat.com>2013-10-28 17:34:42 +0100
commitd1f3a23bfac4fe38056ab5e07186939b7be8852b (patch)
tree2283619f5f9622adddd60bcf76d65f7a22e4bb0b /tests/multiboot
parentd7b7e580096255c766f7b1e7502a9151b95091e8 (diff)
downloadqemu-d1f3a23bfac4fe38056ab5e07186939b7be8852b.zip
tests: Multiboot mmap test case
This adds a test case for Multiboot memory map in the tests/multiboot directory, where future i386 test kernels can be dropped. Because this requires an x86 build host and an installed 32 bit libgcc, the test is not part of a regular 'make check'. The reference output for the test is verified against test runs of the same multiboot kernel booted by some GRUB 0.97. Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'tests/multiboot')
-rw-r--r--tests/multiboot/Makefile18
-rw-r--r--tests/multiboot/libc.c139
-rw-r--r--tests/multiboot/libc.h61
-rw-r--r--tests/multiboot/link.ld19
-rw-r--r--tests/multiboot/mmap.c56
-rw-r--r--tests/multiboot/mmap.out93
-rw-r--r--tests/multiboot/multiboot.h66
-rwxr-xr-xtests/multiboot/run_test.sh81
-rw-r--r--tests/multiboot/start.S51
9 files changed, 584 insertions, 0 deletions
diff --git a/tests/multiboot/Makefile b/tests/multiboot/Makefile
new file mode 100644
index 0000000000..34cdd81a90
--- /dev/null
+++ b/tests/multiboot/Makefile
@@ -0,0 +1,18 @@
+CC=gcc
+CCFLAGS=-m32 -Wall -Wextra -Werror -fno-stack-protector -nostdinc -fno-builtin
+ASFLAGS=-m32
+
+LD=ld
+LDFLAGS=-melf_i386 -T link.ld
+LIBS=$(shell $(CC) $(CCFLAGS) -print-libgcc-file-name)
+
+all: mmap.elf
+
+mmap.elf: start.o mmap.o libc.o
+ $(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+%.o: %.c
+ $(CC) $(CCFLAGS) -c -o $@ $^
+
+%.o: %.S
+ $(CC) $(ASFLAGS) -c -o $@ $^
diff --git a/tests/multiboot/libc.c b/tests/multiboot/libc.c
new file mode 100644
index 0000000000..05abbd92cc
--- /dev/null
+++ b/tests/multiboot/libc.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2013 Kevin Wolf <kwolf@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "libc.h"
+
+static void print_char(char c)
+{
+ outb(0xe9, c);
+}
+
+static void print_str(char *s)
+{
+ while (*s) {
+ print_char(*s++);
+ }
+}
+
+static void print_num(uint64_t value, int base)
+{
+ char digits[] = "0123456789abcdef";
+ char buf[32] = { 0 };
+ int i = sizeof(buf) - 2;
+
+ do {
+ buf[i--] = digits[value % base];
+ value /= base;
+ } while (value);
+
+ print_str(&buf[i + 1]);
+}
+
+void printf(const char *fmt, ...)
+{
+ va_list ap;
+ uint64_t val;
+ char *str;
+ int base;
+ int has_long;
+ int alt_form;
+
+ va_start(ap, fmt);
+
+ for (; *fmt; fmt++) {
+ if (*fmt != '%') {
+ print_char(*fmt);
+ continue;
+ }
+ fmt++;
+
+ if (*fmt == '#') {
+ fmt++;
+ alt_form = 1;
+ } else {
+ alt_form = 0;
+ }
+
+ if (*fmt == 'l') {
+ fmt++;
+ if (*fmt == 'l') {
+ fmt++;
+ has_long = 2;
+ } else {
+ has_long = 1;
+ }
+ } else {
+ has_long = 0;
+ }
+
+ switch (*fmt) {
+ case 'x':
+ case 'p':
+ base = 16;
+ goto convert_number;
+ case 'd':
+ case 'i':
+ case 'u':
+ base = 10;
+ goto convert_number;
+ case 'o':
+ base = 8;
+ goto convert_number;
+
+ convert_number:
+ switch (has_long) {
+ case 0:
+ val = va_arg(ap, unsigned int);
+ break;
+ case 1:
+ val = va_arg(ap, unsigned long);
+ break;
+ case 2:
+ val = va_arg(ap, unsigned long long);
+ break;
+ }
+
+ if (alt_form && base == 16) {
+ print_str("0x");
+ }
+
+ print_num(val, base);
+ break;
+
+ case 's':
+ str = va_arg(ap, char*);
+ print_str(str);
+ break;
+ case '%':
+ print_char(*fmt);
+ break;
+ default:
+ print_char('%');
+ print_char(*fmt);
+ break;
+ }
+ }
+
+ va_end(ap);
+}
+
+
diff --git a/tests/multiboot/libc.h b/tests/multiboot/libc.h
new file mode 100644
index 0000000000..80eec5b7a0
--- /dev/null
+++ b/tests/multiboot/libc.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013 Kevin Wolf <kwolf@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef LIBC_H
+#define LIBC_H
+
+/* Integer types */
+
+typedef unsigned long long uint64_t;
+typedef unsigned int uint32_t;
+typedef unsigned short uint16_t;
+typedef unsigned char uint8_t;
+
+typedef signed long long int64_t;
+typedef signed int int32_t;
+typedef signed short int16_t;
+typedef signed char int8_t;
+
+typedef uint32_t uintptr_t;
+
+
+/* stdarg.h */
+
+typedef __builtin_va_list va_list;
+#define va_start(ap, X) __builtin_va_start(ap, X)
+#define va_arg(ap, type) __builtin_va_arg(ap, type)
+#define va_end(ap) __builtin_va_end(ap)
+
+
+/* Port I/O functions */
+
+static inline void outb(uint16_t port, uint8_t data)
+{
+ asm volatile ("outb %0, %1" : : "a" (data), "Nd" (port));
+}
+
+
+/* Misc functions */
+
+void printf(const char *fmt, ...);
+
+#endif
diff --git a/tests/multiboot/link.ld b/tests/multiboot/link.ld
new file mode 100644
index 0000000000..3d49b58c60
--- /dev/null
+++ b/tests/multiboot/link.ld
@@ -0,0 +1,19 @@
+ENTRY(_start)
+
+SECTIONS
+{
+ . = 0x100000;
+ .text : {
+ *(multiboot)
+ *(.text)
+ }
+ .data ALIGN(4096) : {
+ *(.data)
+ }
+ .rodata ALIGN(4096) : {
+ *(.rodata)
+ }
+ .bss ALIGN(4096) : {
+ *(.bss)
+ }
+}
diff --git a/tests/multiboot/mmap.c b/tests/multiboot/mmap.c
new file mode 100644
index 0000000000..766b003f38
--- /dev/null
+++ b/tests/multiboot/mmap.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013 Kevin Wolf <kwolf@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "libc.h"
+#include "multiboot.h"
+
+int test_main(uint32_t magic, struct mb_info *mbi)
+{
+ uintptr_t entry_addr;
+ struct mb_mmap_entry *entry;
+
+ (void) magic;
+
+ printf("Lower memory: %dk\n", mbi->mem_lower);
+ printf("Upper memory: %dk\n", mbi->mem_upper);
+
+ printf("\ne820 memory map:\n");
+
+ for (entry_addr = mbi->mmap_addr;
+ entry_addr < mbi->mmap_addr + mbi->mmap_length;
+ entry_addr += entry->size + 4)
+ {
+ entry = (struct mb_mmap_entry*) entry_addr;
+
+ printf("%#llx - %#llx: type %d [entry size: %d]\n",
+ entry->base_addr,
+ entry->base_addr + entry->length,
+ entry->type,
+ entry->size);
+ }
+
+ printf("\nmmap start: %#x\n", mbi->mmap_addr);
+ printf("mmap end: %#x\n", mbi->mmap_addr + mbi->mmap_length);
+ printf("real mmap end: %#x\n", entry_addr);
+
+ return 0;
+}
diff --git a/tests/multiboot/mmap.out b/tests/multiboot/mmap.out
new file mode 100644
index 0000000000..e70b6eb45d
--- /dev/null
+++ b/tests/multiboot/mmap.out
@@ -0,0 +1,93 @@
+
+
+
+=== Running test case: mmap.elf ===
+
+Lower memory: 639k
+Upper memory: 130040k
+
+e820 memory map:
+0x0 - 0x9fc00: type 1 [entry size: 20]
+0x9fc00 - 0xa0000: type 2 [entry size: 20]
+0xf0000 - 0x100000: type 2 [entry size: 20]
+0x100000 - 0x7ffe000: type 1 [entry size: 20]
+0x7ffe000 - 0x8000000: type 2 [entry size: 20]
+0xfffc0000 - 0x100000000: type 2 [entry size: 20]
+
+mmap start: 0x9000
+mmap end: 0x9090
+real mmap end: 0x9090
+
+
+=== Running test case: mmap.elf -m 1.1M ===
+
+Lower memory: 639k
+Upper memory: 96k
+
+e820 memory map:
+0x0 - 0x9fc00: type 1 [entry size: 20]
+0x9fc00 - 0xa0000: type 2 [entry size: 20]
+0xf0000 - 0x100000: type 2 [entry size: 20]
+0x100000 - 0x118000: type 1 [entry size: 20]
+0x118000 - 0x11a000: type 2 [entry size: 20]
+0xfffc0000 - 0x100000000: type 2 [entry size: 20]
+
+mmap start: 0x9000
+mmap end: 0x9090
+real mmap end: 0x9090
+
+
+=== Running test case: mmap.elf -m 2G ===
+
+Lower memory: 639k
+Upper memory: 2096120k
+
+e820 memory map:
+0x0 - 0x9fc00: type 1 [entry size: 20]
+0x9fc00 - 0xa0000: type 2 [entry size: 20]
+0xf0000 - 0x100000: type 2 [entry size: 20]
+0x100000 - 0x7fffe000: type 1 [entry size: 20]
+0x7fffe000 - 0x80000000: type 2 [entry size: 20]
+0xfffc0000 - 0x100000000: type 2 [entry size: 20]
+
+mmap start: 0x9000
+mmap end: 0x9090
+real mmap end: 0x9090
+
+
+=== Running test case: mmap.elf -m 4G ===
+
+Lower memory: 639k
+Upper memory: 3668984k
+
+e820 memory map:
+0x0 - 0x9fc00: type 1 [entry size: 20]
+0x9fc00 - 0xa0000: type 2 [entry size: 20]
+0xf0000 - 0x100000: type 2 [entry size: 20]
+0x100000 - 0xdfffe000: type 1 [entry size: 20]
+0xdfffe000 - 0xe0000000: type 2 [entry size: 20]
+0xfffc0000 - 0x100000000: type 2 [entry size: 20]
+0x100000000 - 0x120000000: type 1 [entry size: 20]
+
+mmap start: 0x9000
+mmap end: 0x90a8
+real mmap end: 0x90a8
+
+
+=== Running test case: mmap.elf -m 8G ===
+
+Lower memory: 639k
+Upper memory: 3668984k
+
+e820 memory map:
+0x0 - 0x9fc00: type 1 [entry size: 20]
+0x9fc00 - 0xa0000: type 2 [entry size: 20]
+0xf0000 - 0x100000: type 2 [entry size: 20]
+0x100000 - 0xdfffe000: type 1 [entry size: 20]
+0xdfffe000 - 0xe0000000: type 2 [entry size: 20]
+0xfffc0000 - 0x100000000: type 2 [entry size: 20]
+0x100000000 - 0x220000000: type 1 [entry size: 20]
+
+mmap start: 0x9000
+mmap end: 0x90a8
+real mmap end: 0x90a8
diff --git a/tests/multiboot/multiboot.h b/tests/multiboot/multiboot.h
new file mode 100644
index 0000000000..4eb1fbe5d4
--- /dev/null
+++ b/tests/multiboot/multiboot.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2013 Kevin Wolf <kwolf@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MULTIBOOT_H
+#define MULTIBOOT_H
+
+#include "libc.h"
+
+struct mb_info {
+ uint32_t flags;
+ uint32_t mem_lower;
+ uint32_t mem_upper;
+ uint32_t boot_device;
+ uint32_t cmdline;
+ uint32_t mods_count;
+ uint32_t mods_addr;
+ char syms[16];
+ uint32_t mmap_length;
+ uint32_t mmap_addr;
+ uint32_t drives_length;
+ uint32_t drives_addr;
+ uint32_t config_table;
+ uint32_t boot_loader_name;
+ uint32_t apm_table;
+ uint32_t vbe_control_info;
+ uint32_t vbe_mode_info;
+ uint16_t vbe_mode;
+ uint16_t vbe_interface_seg;
+ uint16_t vbe_interface_off;
+ uint16_t vbe_interface_len;
+} __attribute__((packed));
+
+struct mb_module {
+ uint32_t mod_start;
+ uint32_t mod_end;
+ uint32_t string;
+ uint32_t reserved;
+} __attribute__((packed));
+
+struct mb_mmap_entry {
+ uint32_t size;
+ uint64_t base_addr;
+ uint64_t length;
+ uint32_t type;
+} __attribute__((packed));
+
+#endif
diff --git a/tests/multiboot/run_test.sh b/tests/multiboot/run_test.sh
new file mode 100755
index 0000000000..97a9a49f8b
--- /dev/null
+++ b/tests/multiboot/run_test.sh
@@ -0,0 +1,81 @@
+#!/bin/bash
+
+# Copyright (c) 2013 Kevin Wolf <kwolf@redhat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+QEMU=${QEMU:-"../../x86_64-softmmu/qemu-system-x86_64"}
+
+run_qemu() {
+ local kernel=$1
+ shift
+
+ echo -e "\n\n=== Running test case: $kernel $@ ===\n" >> test.log
+
+ $QEMU \
+ -kernel $kernel \
+ -display none \
+ -device isa-debugcon,chardev=stdio \
+ -chardev file,path=test.out,id=stdio \
+ -device isa-debug-exit,iobase=0xf4,iosize=0x4 \
+ "$@"
+ ret=$?
+
+ cat test.out >> test.log
+}
+
+mmap() {
+ run_qemu mmap.elf
+ run_qemu mmap.elf -m 1.1M
+ run_qemu mmap.elf -m 2G
+ run_qemu mmap.elf -m 4G
+ run_qemu mmap.elf -m 8G
+}
+
+
+make all
+
+for t in mmap; do
+
+ echo > test.log
+ $t
+
+ debugexit=$((ret & 0x1))
+ ret=$((ret >> 1))
+ pass=1
+
+ if [ $debugexit != 1 ]; then
+ echo -e "\e[31m ?? \e[0m $t (no debugexit used, exit code $ret)"
+ pass=0
+ elif [ $ret != 0 ]; then
+ echo -e "\e[31mFAIL\e[0m $t (exit code $ret)"
+ pass=0
+ fi
+
+ if ! diff $t.out test.log > /dev/null 2>&1; then
+ echo -e "\e[31mFAIL\e[0m $t (output difference)"
+ diff -u $t.out test.log
+ pass=0
+ fi
+
+ if [ $pass == 1 ]; then
+ echo -e "\e[32mPASS\e[0m $t"
+ fi
+
+done
diff --git a/tests/multiboot/start.S b/tests/multiboot/start.S
new file mode 100644
index 0000000000..7d33959650
--- /dev/null
+++ b/tests/multiboot/start.S
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013 Kevin Wolf <kwolf@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+.section multiboot
+
+#define MB_MAGIC 0x1badb002
+#define MB_FLAGS 0x0
+#define MB_CHECKSUM -(MB_MAGIC + MB_FLAGS)
+
+.align 4
+.int MB_MAGIC
+.int MB_FLAGS
+.int MB_CHECKSUM
+
+.section .text
+.global _start
+_start:
+ mov $stack, %esp
+ push %ebx
+ push %eax
+ call test_main
+
+ /* Test device exit */
+ outl %eax, $0xf4
+
+ cli
+ hlt
+ jmp .
+
+.section bss
+.space 8192
+stack: