From d1f3a23bfac4fe38056ab5e07186939b7be8852b Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 27 Jun 2013 13:50:05 +0200 Subject: [PATCH] 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 --- tests/multiboot/Makefile | 18 +++++ tests/multiboot/libc.c | 139 ++++++++++++++++++++++++++++++++++++ tests/multiboot/libc.h | 61 ++++++++++++++++ tests/multiboot/link.ld | 19 +++++ tests/multiboot/mmap.c | 56 +++++++++++++++ tests/multiboot/mmap.out | 93 ++++++++++++++++++++++++ tests/multiboot/multiboot.h | 66 +++++++++++++++++ tests/multiboot/run_test.sh | 81 +++++++++++++++++++++ tests/multiboot/start.S | 51 +++++++++++++ 9 files changed, 584 insertions(+) create mode 100644 tests/multiboot/Makefile create mode 100644 tests/multiboot/libc.c create mode 100644 tests/multiboot/libc.h create mode 100644 tests/multiboot/link.ld create mode 100644 tests/multiboot/mmap.c create mode 100644 tests/multiboot/mmap.out create mode 100644 tests/multiboot/multiboot.h create mode 100755 tests/multiboot/run_test.sh create mode 100644 tests/multiboot/start.S 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 + * + * 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 + * + * 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 + * + * 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 + * + * 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 +# +# 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 + * + * 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: -- GitLab