# Default compiler flags
COMMONCFLAGS = -Wall -Os -MD -m32 -march=i386 -mregparm=3 \
-mpreferred-stack-boundary=2 -mrtd -freg-struct-return \
- $(call cc-option,$(CC),-fwhole-program -DWHOLE_PROGRAM,) \
-ffreestanding -fomit-frame-pointer \
-fno-delete-null-pointer-checks -Wno-strict-aliasing \
- -ffunction-sections -fdata-sections \
+ -ffunction-sections -fdata-sections -fno-common \
-minline-all-stringops
COMMONCFLAGS += $(call cc-option,$(CC),-nopie,)
COMMONCFLAGS += $(call cc-option,$(CC),-fno-stack-protector,)
################ Build rules
+# Verify the gcc configuration and test if -fwhole-program works.
TESTGCC:=$(shell CC=$(CC) tools/test-gcc.sh)
ifeq "$(TESTGCC)" "-1"
$(error "Please upgrade GCC")
endif
-ifndef AVOIDCOMBINE
-AVOIDCOMBINE=$(TESTGCC)
+ifndef COMPSTRAT
+COMPSTRAT=$(TESTGCC)
endif
-# Do a whole file compile - two methods are supported. The first
-# involves including all the content textually via #include
-# directives. The second method uses gcc's "-combine" option.
-ifeq "$(AVOIDCOMBINE)" "1"
+# Do a whole file compile - three methods are supported.
+ifeq "$(COMPSTRAT)" "1"
+# First method - use -fwhole-program without -combine.
+define whole-compile
+@echo " Compiling whole program $3"
+$(Q)printf '$(foreach i,$2,#include "../$i"\n)' > $3.tmp.c
+$(Q)$(CC) $1 -fwhole-program -DWHOLE_PROGRAM -c $3.tmp.c -o $3
+endef
+else ifeq "$(COMPSTRAT)" "2"
+# Second menthod - don't use -fwhole-program at all.
define whole-compile
@echo " Compiling whole program $3"
$(Q)printf '$(foreach i,$2,#include "../$i"\n)' > $3.tmp.c
$(Q)$(CC) $1 -c $3.tmp.c -o $3
endef
else
+# Third (and preferred) method - use -fwhole-program with -combine
define whole-compile
@echo " Compiling whole program $3"
-$(Q)$(CC) $1 -combine -c $2 -o $3
+$(Q)$(CC) $1 -fwhole-program -DWHOLE_PROGRAM -combine -c $2 -o $3
endef
endif
To build, one should be able to run "make" in the main directory. The
resulting file "out/bios.bin" contains the processed bios image.
-The build requires gcc v4.1 or later. Some buggy versions of gcc have
-issues with the '-combine' compiler option - in particular, recent
-versions of Ubuntu are affected. One can use "make AVOIDCOMBINE=1" to
-get around this.
-
Testing of images:
The src/ directory contains the bios source code. Several of the
files are compiled twice - once for 16bit mode and once for 32bit
-mode. (The gcc compile option '-fwhole-program' is used to remove
-code that is not needed for a particular mode.)
+mode. (The build system will remove code that is not needed for a
+particular mode.)
The tools/ directory contains helper utilities for manipulating and
building the final rom.
Build overview:
The 16bit code is compiled via gcc to assembler (file out/ccode.16.s).
-The gcc "-fwhole-program" option is used to optimize the process so
-that gcc can efficiently compile and discard unneeded code. (In the
-code, one can use the macros 'VISIBLE16' and 'VISIBLE32' to instruct a
-symbol to be outputted in 16bit and 32bit mode respectively.)
+The gcc "-fwhole-program" and "-ffunction-sections -fdata-sections"
+options are used to optimize the process so that gcc can efficiently
+compile and discard unneeded code. (In the code, one can use the
+macros 'VISIBLE16' and 'VISIBLE32' to instruct a symbol to be
+outputted in 16bit and 32bit mode respectively.)
This resulting assembler code is pulled into romlayout.S. The gas
option ".code16gcc" is used prior to including the gcc generated
to simplify these accesses.
Global variables defined in the C code can be read in 16bit mode if
-the variable declaration is marked with VAR16 or VAR16_32. The
-GET_GLOBAL macro will then allow read access to the variable. Global
-variables are stored in the 0xf000 segment, and their values are
-persistent across soft resets. Because the f-segment is marked
-read-only during run-time, the 16bit code is not permitted to change
-the value of 16bit variables (use of the SET_GLOBAL macro from 16bit
-mode will cause a link error). Code running in 32bit mode can not
-access variables with VAR16, but can access variables marked with
-VAR16_32 or with no marking at all. The 32bit code can use the
-GET/SET_GLOBAL macros, but they are not required.
+the variable declaration is marked with VAR16, VAR16_32, VAR16EXPORT,
+or VAR16FIXED. The GET_GLOBAL macro will then allow read access to
+the variable. Global variables are stored in the 0xf000 segment, and
+their values are persistent across soft resets. Because the f-segment
+is marked read-only during run-time, the 16bit code is not permitted
+to change the value of 16bit variables (use of the SET_GLOBAL macro
+from 16bit mode will cause a link error). Code running in 32bit mode
+can not access variables with VAR16, but can access variables marked
+with VAR16_32, VAR16EXPORT, VAR16FIXED, or with no marking at all.
+The 32bit code can use the GET/SET_GLOBAL macros, but they are not
+required.
GCC 16 bit stack limitations:
an extra stack stored in the EBDA using the stack_hop helper function.
Some useful stats: the overhead for the entry to a bios handler that
-takes a 'struct bregs' is 38 bytes of stack space (6 bytes from
-interrupt insn, 28 bytes to store registers, and 4 bytes for call
+takes a 'struct bregs' is 42 bytes of stack space (6 bytes from
+interrupt insn, 32 bytes to store registers, and 4 bytes for call
insn). An entry to an ISR handler without args takes 30 bytes (6 + 20
+ 4).
SET_EBDA(boot_sequence, 0);
do_boot(0);
}
-
-// Ughh - some older gcc compilers have a bug which causes VISIBLE32
-// functions to not be exported as global variables.
-asm(".global handle_18, handle_19");
memset(&br, 0, sizeof(br));
call16_int(0x19, &br);
}
-
-// Ughh - some older gcc compilers have a bug which causes VISIBLE32
-// functions to not be exported as a global variable - force _start
-// to be global here.
-asm(".global _start");
call16big(&br);
}
#endif
-
-// Ughh - some older gcc compilers have a bug which causes VISIBLE32
-// functions to not be exported as global variables.
-asm(".global s3_resume");
$CC -fwhole-program -S -o /dev/null -xc /dev/null > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo " Working around no -fwhole-program" > /dev/fd/2
- echo 1
+ echo 2
exit 0
fi
-# Test if "visible" variables are marked global.
-cat - > $TMPFILE1 <<EOF
-unsigned char t1 __attribute__((section(".data16.foo.19"))) __attribute__((externally_visible));
-EOF
-$CC -Os -c -fwhole-program $TMPFILE1 -o $TMPFILE1o > /dev/null 2>&1
-cat - > $TMPFILE2 <<EOF
-extern unsigned char t1;
-int __attribute__((externally_visible)) main() { return t1; }
-EOF
-$CC -Os -c -fwhole-program $TMPFILE2 -o $TMPFILE2o > /dev/null 2>&1
-$CC -nostdlib -Os $TMPFILE1o $TMPFILE2o -o $TMPFILE3o > /dev/null 2>&1
-if [ $? -ne 0 ]; then
- echo "This version of gcc does not properly handle" > /dev/fd/2
- echo " global variables in -fwhole-program mode." > /dev/fd/2
- echo "Please upgrade to a newer gcc (eg, v4.3 or later)" > /dev/fd/2
- echo -1
- exit 1
-fi
-
-# Test if "visible" functions are marked global.
+# Test if "visible" variables and functions are marked global.
cat - > $TMPFILE1 <<EOF
void __attribute__((externally_visible)) t1() { }
+unsigned char v1 __attribute__((section(".data16.foo.19"))) __attribute__((externally_visible));
EOF
$CC -Os -c -fwhole-program $TMPFILE1 -o $TMPFILE1o > /dev/null 2>&1
cat - > $TMPFILE2 <<EOF
void t1();
-void __attribute__((externally_visible)) main() { t1(); }
+extern unsigned char v1;
+int __attribute__((externally_visible)) main() { t1(); return v1; }
EOF
$CC -Os -c -fwhole-program $TMPFILE2 -o $TMPFILE2o > /dev/null 2>&1
$CC -nostdlib -Os $TMPFILE1o $TMPFILE2o -o $TMPFILE3o > /dev/null 2>&1
if [ $? -ne 0 ]; then
- echo " Working around non-global functions in -fwhole-program" > /dev/fd/2
+ echo " Working around non-functional -fwhole-program" > /dev/fd/2
+ echo 2
+ exit 0
fi
# Test if "-combine" works