You are not logged in.
Hi everyone!
I have a problem running two guests in qemu and getting them to communicate over a network. The guests are running a homemade i386 OS, to which RTL8139 drivers were added recently. Currently, only a simple ethernet example is implemented, with the guest OSes sending ethernet frames to each other. The code is working correctly, as it has been tested on Ubuntu 16.04 recently, and Arch a while ago. But something must have changed on Arch recently, as currently starting the demo works, but the guests can't communicate with each other.
This is the makefile for the project:
# Building system script (for 'make')
# valid targets: (all), clean, cleanall, qemu, debug_qemu, debug_gdb
# valid command line defines: debug=yes, optimize=yes
#default target
ARCH ?= i386
CONFIG_INI = arch/$(ARCH)/config.ini
THIS_MAKEFILE = Makefile
CONFIG_FILES = $(CONFIG_INI) $(THIS_MAKEFILE)
include $(CONFIG_INI)
KERNEL_FILE_NAME = $(PROJECT).elf
BINFILE = $(BUILDDIR)/$(KERNEL_FILE_NAME)
CMACROS += OS_NAME="\"$(OS_NAME)\"" PROJECT="\"$(PROJECT)\"" \
NAME_MAJOR="\"$(NAME_MAJOR)\"" NAME_MINOR="\"$(NAME_MINOR)\""\
ARCH="\"$(ARCH)\"" AUTHOR="\"$(AUTHOR)\"" \
VERSION="\"$(VERSION)\""
#------------------------------------------------------------------------------
# Devices
#little "magic" for automatically setting DEV_VARS and DEV_PTRS
#with changes only in DEVICES_DEV (for kernel/devices.c):
# DEV_VARS = vga_text_dev,uart_com1,i8042_dev
# DEV_PTRS = &vga_text_dev,&uart_com1,&i8042_dev
comma := ,
empty :=
space := $(empty) $(empty)
DEV_VARS := $(subst $(space),$(comma),$(DEVICES_DEV))
DEV_PTRS := $(addprefix \&,$(DEVICES_DEV))
DEV_PTRS := $(subst $(space),$(comma),$(DEV_PTRS))
CMACROS += $(DEVICES) DEVICES_DEV=$(DEV_VARS) DEVICES_DEV_PTRS=$(DEV_PTRS) \
IC_DEV=$(IC_DEV) TIMER=$(TIMER) \
K_INITIAL_STDOUT=$(K_INITIAL_STDOUT) K_STDOUT="\"$(K_STDOUT)\"" \
U_STDIN="\"$(U_STDIN)\"" U_STDOUT="\"$(U_STDOUT)\"" \
U_STDERR="\"$(U_STDERR)\""
CMACROS += MAX_RESOURCES=$(MAX_RESOURCES)
#------------------------------------------------------------------------------
# Threads
CMACROS += SYSTEM_MEMORY=$(SYSTEM_MEMORY) \
PRIO_LEVELS=$(PRIO_LEVELS) \
THR_DEFAULT_PRIO=$(THR_DEFAULT_PRIO) \
KERNEL_STACK_SIZE=$(KERNEL_STACK_SIZE) \
DEFAULT_THREAD_STACK_SIZE=$(DEFAULT_THREAD_STACK_SIZE) \
PROG_HEAP_SIZE=$(PROG_HEAP_SIZE) \
HANDLER_STACK_SIZE=$(HANDLER_STACK_SIZE) \
LOAD_ADDR=$(LOAD_ADDR)
#------------------------------------------------------------------------------
CMACROS += $(OPTIONALS)
#------------------------------------------------------------------------------
all: $(BINFILE)
# Create $(BUILDDIR) and ARCH symbolic link for selected platform source
# (used for #include <ARCH/*> purposes)
BDIR_RDY = $(BUILDDIR)/.null
$(BDIR_RDY):
@mkdir -p $(BUILDDIR)
@ln -s ../arch/$(ARCH) $(BUILDDIR)/ARCH
@touch $(BDIR_RDY)
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Compiling and linking kernel
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
BUILD_K = $(BUILDDIR)/kernel
CMACROS_K += $(CMACROS) ASSERT_H=\<kernel/errno.h\>
#------------------------------------------------------------------------------
# Memory allocators: 'gma' and/or 'first_fit'
CMACROS_K += MEM_ALLOCATOR_FOR_KERNEL=$(MEM_ALLOCATOR_FOR_KERNEL)
#------------------------------------------------------------------------------
FILES_K := $(foreach DIR,$(DIRS_K),$(wildcard $(DIR)/*.c $(DIR)/*.S))
OBJS_K := $(addprefix $(BUILD_K)/,$(FILES_K:.c=.o))
OBJS_K := $(OBJS_K:.S=.asm.o)
DEPS_K := $(OBJS_K:.o=.d)
# dummy file that indicate directories for kernel objects are created
KDIRS_CREATED = $(BUILD_K)/.null
# create required directories in $(BUILD_K) directory (including $(BUILD_K))
$(KDIRS_CREATED): $(BDIR_RDY)
@-if [ ! -e $(BUILD_K) ]; then mkdir -p $(BUILD_K); fi;
@-$(foreach DIR,$(DIRS_K), if [ ! -e $(BUILD_K)/$(DIR) ]; \
then mkdir -p $(BUILD_K)/$(DIR); fi; )
@touch $(KDIRS_CREATED)
# define how to compile .c files
$(BUILD_K)/%.o: %.c $(CONFIG_FILES) $(KDIRS_CREATED)
@echo [compiling 'kernel'] $< ...
@$(CC_K) -c $< -o $@ -MMD $(CFLAGS_K) \
$(foreach INC,$(INCLUDES_K),-I $(INC)) \
$(foreach MACRO,$(CMACROS_K),-D $(MACRO))
# define how to compile .S files (assembler)
$(BUILD_K)/%.asm.o: %.S $(CONFIG_FILES) $(KDIRS_CREATED)
@echo [compiling 'kernel'] $< ...
@$(CC_K) -c $< -o $@ -MMD $(CFLAGS_K) \
$(foreach INC,$(INCLUDES_K),-I$(INC)) \
$(foreach MACRO,$(CMACROS_K),-D $(MACRO))
# preprocessed linker script (constants)
LDSCRIPT_PP := $(BUILD_K)/ldscript.ld
$(LDSCRIPT_PP): $(LDSCRIPT) $(CONFIG_FILES) $(KDIRS_CREATED)
@$(CC_K) -E -P -x c -o $@ $< $(CFLAGS_K) \
$(foreach INC,$(INCLUDES_K),-I$(INC)) \
$(foreach MACRO,$(CMACROS_K),-D $(MACRO))
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Compiling and linking programs
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
PROG := progs
BUILD_U := $(BUILDDIR)/$(PROG)
PROG_HEADERS := $(PROG)/programs.h
CMACROS_U += $(CMACROS) ASSERT_H=\<api/errno.h\> \
PROGRAMS=\<$(PROG_HEADERS)\> \
PROG_START_FUNC=$(PROG_START_FUNC) \
MEM_ALLOCATOR_FOR_USER=$(MEM_ALLOCATOR_FOR_USER) \
MAX_USER_DESCRIPTORS=$(MAX_USER_DESCRIPTORS)
PROGRAM_HEADERS := $(BUILDDIR)/$(PROG_HEADERS)
#------------------------------------------------------------------------------
UDIR_RDY = $(BUILD_U)/.null
$(UDIR_RDY): $(BDIR_RDY)
@-if [ ! -e $(BUILD_U) ]; then mkdir -p $(BUILD_U); fi;
@touch $(UDIR_RDY)
# Programs compilation through template ----------------------------------------
# Template is parsed twice:
# 1) when "called" - when expanded on every "call" location;
# all "simple" variables and functions are evaluated
# (variables and functions defined with single $ character)
# Other ("complex") variables and function are left (but one $ is removed)
# 2) when "final" makefile is parsed
# Template is called with: $(call PROGRAM_TEMPLATE,prog_name)
# for example: $(call PROGRAM_TEMPLATE,hello) => $(1) is hello
define PROGRAM_TEMPLATE
$(1)_MACROS := $(CMACROS_U) PROG_HELP=$(1)_prog_help_msg
$(1)_DIRS := $(wordlist 2,$(words $($(1))),$($(1)))
$(1)_FILES := $$(foreach DIR,$$($(1)_DIRS),$$(wildcard $$(DIR)/*.c $$(DIR)/*.S))
$(1)_BUILDDIR := $(BUILD_U)/$(1)
$(1)_BDIRS := $$(addprefix $$($(1)_BUILDDIR)/,$$($(1)_DIRS))
$(1)_OBJS := $$(addprefix $$($(1)_BUILDDIR)/,$$($(1)_FILES))
$(1)_OBJS := $$($(1)_OBJS:.c=.o)
$(1)_OBJS := $$($(1)_OBJS:.S=.asm.o)
$(1)_DEPS := $$($(1)_OBJS:.o=.d)
FILES_U += $$($(1)_FILES)
OBJS_U += $$($(1)_OBJS)
DEPS_U += $$($(1)_DEPS)
# dummy file that indicate directories are created
$(1)_DIRS_CREATED := $$($(1)_BUILDDIR)/.null
#create directories for objects
$$($(1)_DIRS_CREATED): $(UDIR_RDY)
@if [ ! -e $$($(1)_BUILDDIR) ]; then mkdir -p $$($(1)_BUILDDIR); fi;
@$$(foreach DIR,$$($(1)_BDIRS), if [ ! -e $$(DIR) ]; \
then mkdir -p $$(DIR); fi; )
@touch $$($(1)_DIRS_CREATED)
#define how to compile .c files
$$($(1)_BUILDDIR)/%.o: %.c $(CONFIG_FILES) $$($(1)_DIRS_CREATED) $(PROGRAM_HEADERS)
@echo [compiling '$(1)'] $$< ...
@$$(CC_U) -c $$< -o $$@ -MMD $$(CFLAGS_U) \
$$(foreach INC,$$(INCLUDES_U),-I $$(INC)) \
$$(foreach MACRO,$$($(1)_MACROS),-D $$(MACRO))
#define how to compile .S files (assembler)
$$($(1)_BUILDDIR)/%.asm.o: %.S $(CONFIG_FILES) $$($(1)_DIRS_CREATED) $(PROGRAM_HEADERS)
@echo [compiling '$(1)'] $$< ...
@$$(CC_U) -c $$< -o $$@ -MMD $$(CFLAGS_U) \
$$(foreach INC,$$(INCLUDES_U),-I$$(INC)) \
$$(foreach MACRO,$$($(1)_MACROS),-D $$(MACRO))
endef
# "Call" above template for each program to be included
$(foreach prog,$(CCPROGRAMS),$(eval $(call PROGRAM_TEMPLATE,$(prog))))
$(PROGRAM_HEADERS): $(FILES_U) $(UDIR_RDY)
@-if [ ! -e $(BUILD_U) ]; then mkdir -p $(BUILD_U); fi;
@-rm -f $(PROGRAM_HEADERS)
@$(foreach prog,$(PROGRAMS), \
echo "int $(word 1,$($(prog))) ( char *args[] );" \
>> $(PROGRAM_HEADERS); )
@echo "#define PROGRAMS_FOR_SHELL { \\" >> $(PROGRAM_HEADERS)
@$(foreach prog,$(PROGRAMS), \
echo "{ $(word 1,$($(prog))), \"$(prog)\", \" \" }, \\" \
>> $(PROGRAM_HEADERS); )
@echo "{NULL,NULL,NULL} }" >> $(PROGRAM_HEADERS)
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
OBJECTS = $(OBJS_K) $(OBJS_U)
DEPS = $(DEPS_K) $(DEPS_U)
# OS image
$(BINFILE): $(OBJECTS) $(LDSCRIPT_PP)
@echo [linking $@]
@$(LINK) -o $@ $(OBJECTS) -T $(LDSCRIPT_PP) $(LDFLAGS)
# starting compiled system in 'qemu' emulator
qemu: all
@echo $(QMSG)
@$(QEMU) $(QFLAGS) -kernel $(BINFILE)
# DEBUGGING
# For debugging to work: include '-g' in CFLAGS and omit -s and -S from LDFLAGS
# Best if -O3 flag is also omitted from CFLAGS and LDFLAGS (or some variables
# may be optimized away)
# Start debugging from two consoles:
# 1st: make debug_qemu
# 2nd: make debug_gdb
debug_qemu: all
@echo $(QMSG)
@$(QEMU) $(QFLAGS) -kernel $(BINFILE) -s -S
debug_gdb: all
@echo Starting gdb ...
@$(DEBUG_GDB) -s $(BINFILE) -ex 'target remote localhost:1234'
net_qemu: all
@echo Starting qemu and network $(QEMU_MEM)
@xterm -fg black -bg white -e $(QEMU) $(QFLAGS) -kernel $(BINFILE) -device rtl8139,netdev=vlan,mac=52:54:00:12:34:56 -netdev socket,id=vlan,listen=localhost:1234 &
@xterm -fg black -bg white -e $(QEMU) $(QFLAGS) -kernel $(BINFILE) -device rtl8139,netdev=vlan,mac=52:54:00:12:34:57 -netdev socket,id=vlan,connect=localhost:1234 &
clean:
@echo Cleaning.
@-rm -f $(OBJECTS) $(DEPS) $(BINFILE)
clean_all cleanall:
@echo Removing build directory!
@-rm -rf $(BUILDDIR)
-include $(DEPS)
And this is the config.ini file included in the makefile:
# Configuration file (included from Makefile)
# Common configuration
#------------------------------------------------------------------------------
OS_NAME = "Benu"
NAME_MAJOR := $(shell basename "`cd ..; pwd -P`")
NAME_MINOR := $(shell basename "`pwd -P`")
PROJECT := $(NAME_MINOR)
ARCH ?= i386
VERSION = 1.0
AUTHOR = leonardo@zemris.fer.hr
# Intermediate and output files are placed into BUILDDIR
BUILDDIR = build
# Where will system be loaded when started (for which address to prepare it)
LOAD_ADDR = 0x100000
OPTIONALS =
# Devices
#------------------------------------------------------------------------------
#"defines" (which device drivers to compile)
DEVICES = VGA_TEXT I8042 I8259 I8253 UART RTL_8139
#devices interface (variables implementing device_t interface)
DEVICES_DEV = dev_null vga_text_dev uart_com1 i8042_dev rtl_8139_dev
#interrupt controller device
IC_DEV = i8259
#timer device
TIMER = i8253
#initial standard output device (while "booting up")
K_INITIAL_STDOUT = uart_com1
#K_INITIAL_STDOUT = vga_text_dev
#standard output for kernel function (for kprint) - device name
K_STDOUT = COM1
#K_STDOUT = VGA_TXT
#standard output and input devices for programs
U_STDIN = COM1
U_STDOUT = COM1
U_STDERR = COM1
#U_STDIN = i8042
#U_STDOUT = VGA_TXT
#U_STDERR = VGA_TXT
# System resources
#------------------------------------------------------------------------------
MAX_RESOURCES = 1000
PRIO_LEVELS = 64
THR_DEFAULT_PRIO = 20
KERNEL_STACK_SIZE = 0x1000
DEFAULT_THREAD_STACK_SIZE = 0x1000
PROG_HEAP_SIZE = 0x10000
HANDLER_STACK_SIZE = 0x400
# System memory (in Bytes)
SYSTEM_MEMORY = 0x800000
# Memory allocators to compile
#------------------------------------------------------------------------------
FIRST_FIT = 1
GMA = 2
#define which to compile
OPTIONALS += FIRST_FIT=$(FIRST_FIT) GMA=$(GMA)
# If using FPU/SSE/MMX, extended context must be saved (uncomment following)
# OPTIONALS += USE_SSE
# Use simple round robin scheduler?
OPTIONALS += SCHED_RR_SIMPLE
OPTIONALS += SCHED_RR_TICK=10000000 #10 ms tick
# Library with utility functions (strings, lists, ...)
#------------------------------------------------------------------------------
LIBS = lib lib/mm
# Compiling and linking: common parameters
#------------------------------------------------------------------------------
LINK = ld
LDSCRIPT = $(BUILDDIR)/ARCH/boot/ldscript.ld
LDFLAGS = -melf_i386
LDFLAGS_OPT = -O3 --gc-sections -s
LDFLAGS_OPTD = -O3 --gc-sections
# Compiling and linking: kernel
#------------------------------------------------------------------------------
CC_K = gcc
CFLAGS_K = -m32 -march=i386 -Wall -Werror -nostdinc -ffreestanding -nostdlib -fno-stack-protector
# additional optimization flags
CFLAGS_KOPT = -O3 -fdata-sections -ffunction-sections
#optimization with debug information
CFLAGS_KOPTD = -O3 -fdata-sections -ffunction-sections -g
#if in command line given: debug=yes or/and optimize=yes
ifeq ($(optimize),yes)
ifeq ($(debug),yes) #if both are set!
CFLAGS_K += $(CFLAGS_KOPTD)
LDFLAGS += $(LDFLAGS_OPTD)
CMACROS += DEBUG
else
CFLAGS_K += $(CFLAGS_KOPT)
LDFLAGS += $(LDFLAGS_OPT)
endif
else #debug set by default
CFLAGS_K += -g
CMACROS += DEBUG
endif
# directories to include while compiling kernel
DIRS_K := arch/$(ARCH)/boot arch/$(ARCH) arch/$(ARCH)/drivers \
kernel $(LIBS)
# include dirs for kernel ($(BUILDDIR) for ARCH layer)
INCLUDES_K := include $(BUILDDIR)
# Memory allocator for kernel: 'GMA' or 'FIRST_FIT'
MEM_ALLOCATOR_FOR_KERNEL = $(FIRST_FIT)
CMACROS_K += _KERNEL_
# Compiling and linking: programs
#------------------------------------------------------------------------------
CC_U = gcc
CFLAGS_U = -m32 -march=i386 -Wall -Werror -nostdinc -ffreestanding -nostdlib -fno-stack-protector
# additional optimization flags
CFLAGS_UOPT = -O3 -fdata-sections -ffunction-sections
#optimization with debug information
CFLAGS_UOPTD = -O3 -fdata-sections -ffunction-sections -g
#if in command line given: debug=yes or/and optimize=yes
ifeq ($(optimize),yes)
ifeq ($(debug),yes) #if both are set!
CFLAGS_U += $(CFLAGS_UOPTD)
else
CFLAGS_U += $(CFLAGS_UOPT)
endif
else #debug set by default
CFLAGS_U += -g
endif
DIRS_U := api
INCLUDES_U := include/api include $(BUILDDIR)
# Memory allocator for programs: 'GMA' or 'FIRST_FIT'
MEM_ALLOCATOR_FOR_USER = $(GMA)
MAX_USER_DESCRIPTORS = 10
# Programs to include in compilation
PROGRAMS = pci_enumeration
# Define each program with:
# prog_name = 1_starting-routine 2_directories
hello = hello_world programs/hello_world
timer = timer programs/timer
signals = signals programs/signals
keyboard = keyboard programs/keyboard
shell = shell programs/shell
args = arguments programs/arguments
uthreads = user_threads programs/user_threads
threads = threads programs/threads
semaphores = semaphores programs/semaphores
monitors = monitors programs/monitors
messages = messages programs/messages
sse_test = sse_test programs/sse_test
segm_fault = segm_fault programs/segm_fault
rr = round_robin programs/round_robin
run_all = run_all programs/run_all
pci_enumeration = pci_enumeration programs/pci_enumeration
eth_example = eth_example programs/eth_example
common = null api
CCPROGRAMS = common $(PROGRAMS)
#initial program to be started at end of kernel initialization
START_WITH ?= pci_enumeration
PROG_START_FUNC = $(START_WITH)
QEMU_MEM = $(shell echo $$(( ($(SYSTEM_MEMORY)-1)/1048576+1 )) )
QEMU = qemu-system-$(ARCH)
QFLAGS = -m $(QEMU_MEM)M -no-kvm-irqchip -no-kvm -serial stdio -display none
# If using VGA_TXT output remove "-display none" from qemu arguments
QMSG = "Starting qemu"
DEBUG_GDB = gdb
Now, it's a bit of a mess, from people who have worked on the project before me, so here's the relevant part, where the guests are run, with the variables expanded to their values:
net_qemu: all
@echo Starting qemu and network $(shell echo $$(( (0x800000-1)/1048576+1 )) )
@xterm -fg black -bg white -e qemu-system-i386 -m $(shell echo $$(( (0x800000-1)/1048576+1 )) )M -no-kvm-irqchip -no-kvm -serial stdio -display none -kernel $(BUILDDIR)/$(KERNEL_FILE_NAME) -device rtl8139,netdev=vlan,mac=52:54:00:12:34:56 -netdev socket,id=vlan,listen=localhost:1234 &
@xterm -fg black -bg white -e qemu-system-i386 -m $(shell echo $$(( (0x800000-1)/1048576+1 )) )M -no-kvm-irqchip -no-kvm -serial stdio -display none -kernel $(BUILDDIR)/$(KERNEL_FILE_NAME) -device rtl8139,netdev=vlan,mac=52:54:00:12:34:57 -netdev socket,id=vlan,connect=localhost:1234 &
All the files were the same when trying both on Ubuntu and on Arch. Ubuntu qemu version is 2.5, while the Arch version is 2.10.1. Did I miss something? Did qemu remove support for this?
Offline
Hi everyone!
Did qemu remove support for this?
Looks like they've changed syntax for "-netdev socket" - there's no listen/connect directives now. Check man qemu on 2.10.1.
Offline
Well, from what I can see in man, the listen and connect directives are still there. But I've tried without them, and now both guests don't even start, saying:
net_init_socket: Assertion 'sock->has_udp' has failed.
This was the previous qemu directive, which also works on Ubuntu but not on arch:
net_qemu: all
@echo Starting qemu and network $(shell echo $$(( (0x800000-1)/1048576+1 )) )
@xterm -fg black -bg white -e qemu-system-i386 -m $(shell echo $$(( (0x800000-1)/1048576+1 )) )M -no-kvm-irqchip -no-kvm -serial stdio -display none -kernel $(BUILDDIR)/$(KERNEL_FILE_NAME) -net nic,vlan=1,model=rtl8139,macaddr=52:54:00:12:34:56 -net socket,vlan=1,listen=localhost:1234 &
@xterm -fg black -bg white -e qemu-system-i386 -m $(shell echo $$(( (0x800000-1)/1048576+1 )) )M -no-kvm-irqchip -no-kvm -serial stdio -display none -kernel $(BUILDDIR)/$(KERNEL_FILE_NAME) -net nic,vlan=1,model=rtl8139,macaddr=52:54:00:12:34:57 -net socket,vlan=1,connect=localhost:1234 &
EDIT: I have confirmed it to be an Arch issue, as it works on Ubuntu 17.10 with the same qemu version, 2.10.1.
Last edited by Dafta (2017-12-04 16:46:08)
Offline