bonzini / qboot

Minimal x86 firmware for booting Linux kernels
GNU General Public License v2.0
704 stars 118 forks source link

inconsistent operand constraints in an 'asm' #4

Closed davedoesdev closed 9 years ago

davedoesdev commented 9 years ago

I'm getting this error:

cc -O2 -g -MMD -MF .deps/cc-.-main.d -Wall -m32 -march=i386 -mregparm=3 -fno-stack-protector -fno-delete-null-pointer-checks -ffreestanding -Iinclude -c -s main.c -o main.o
main.c: In function 'main':
include/ioport.h:11: error: inconsistent operand constraints in an 'asm'
include/ioport.h:11: error: inconsistent operand constraints in an 'asm'
include/ioport.h:11: error: inconsistent operand constraints in an 'asm'
make: *** [main.o] Error 1

I'm using GCC 4.2.1.

davedoesdev commented 9 years ago

This fixes it but it seems a bit strange to me:

--- include/ioport.h.orig
+++ include/ioport.h
@@ -8,7 +8,7 @@

 static inline void insb(void *buf, unsigned short port, int len)
 {
-   asm volatile("rep insb %3, %%es:(%0)" : "+D" (buf), "+c" (len), "=m"(buf) : "Nd"(port), "0" (buf), "1" (len));
+   asm volatile("rep insb %3, %%es:(%0)" : "+D" (buf), "=c" (len), "=m"(buf) : "Nd"(port), "c" (len), "0" (buf), "1" (len));
 }

 static inline unsigned char inb(unsigned short port)

Also, does it need a "memory" clobber?

bonzini commented 9 years ago

What about this instead?

diff --git a/include/ioport.h b/include/ioport.h
index bbec982..208be41 100644
--- a/include/ioport.h
+++ b/include/ioport.h
@@ -3,12 +3,12 @@

 static inline void outsb(unsigned short port, void *buf, int len)
 {
-   asm volatile("rep outsb %%ds:(%0), %3" : "+S" (buf), "+c" (len) : "m"(buf), "Nd"(port), "0" (buf), "1" (len));
+   asm volatile("rep outsb %%ds:(%0), %3" : "=S" (buf), "=c" (len) : "m"(buf), "Nd"(port), "0" (buf), "1" (len));
 }

 static inline void insb(void *buf, unsigned short port, int len)
 {
-   asm volatile("rep insb %3, %%es:(%0)" : "+D" (buf), "+c" (len), "=m"(buf) : "Nd"(port), "0" (buf), "1" (len));
+   asm volatile("rep insb %3, %%es:(%0)" : "=D" (buf), "=c" (len), "=m"(buf) : "Nd"(port), "0" (buf), "1" (len));
 }

 static inline unsigned char inb(unsigned short port)
davedoesdev commented 9 years ago

Yep, that works - thanks

davedoesdev commented 9 years ago

It boots too when bios.bin is compiled on Ubuntu 14.10. However, when I compile bios.bin using GCC 4.2.1 and uClibc it doesn't (qemu just exits straight away). Is there any useful way to debug what's happening there?

davedoesdev commented 9 years ago

Problem is main wasn't being put at start. This fixes it (thanks to http://stackoverflow.com/questions/19470666/gcc-how-to-tell-gcc-to-put-the-main-function-at-the-start-of-the-text-sectio?rq=1):

--- wup/qboot-d1da38e16592f6f541d0fa9aa675fa296585f779/Makefile
+++ qboot-d1da38e16592f6f541d0fa9aa675fa296585f779/Makefile
@@ -26,7 +26,7 @@
    $(CC) $(CFLAGS) $(BIOS_CFLAGS) -c -s $< -o $@

 bios.bin.elf: $(obj-y) flat.lds
-   $(LD) -T flat.lds -o bios.bin.elf $(obj-y)
+   $(LD) -m elf_i386 -T flat.lds -o bios.bin.elf $(obj-y)

 bios.bin: bios.bin.elf
    objcopy -O binary bios.bin.elf bios.bin
--- wup/qboot-d1da38e16592f6f541d0fa9aa675fa296585f779/flat.lds
+++ qboot-d1da38e16592f6f541d0fa9aa675fa296585f779/flat.lds
@@ -4,7 +4,7 @@
 {
     . = 1024K - 64K;
     stext = .;
-    .text : { *(.text.startup) *(.text) *(.text.*) }
+    .text : { *(.text.startup) *(entry) *(.text) *(.text.*) }
     . = ALIGN(16);
     .data : { *(.data) }
     . = ALIGN(16);
--- wup/qboot-d1da38e16592f6f541d0fa9aa675fa296585f779/main.c
+++ qboot-d1da38e16592f6f541d0fa9aa675fa296585f779/main.c
@@ -78,6 +78,7 @@
    return boot_from_cbfs(base, sz);
 }

+int main(void) __attribute__ ((section ("entry")));
 int main(void)
 {
    setup_hw();
bonzini commented 9 years ago

And is this enough?

diff --git a/main.c b/main.c
index 86bd3fd..b376c0d 100644
--- a/main.c
+++ b/main.c
@@ -78,7 +78,7 @@ static bool detect_cbfs_and_boot(void)
    return boot_from_cbfs(base, sz);
 }

-int main(void)
+int __attribute__ ((section (".text.startup"))) main(void)
 {
    setup_hw();
davedoesdev commented 9 years ago

@bonzini yes that is enough to make it work

davedoesdev commented 9 years ago

Btw @bonzini how did you conduct the measurement of boot times? I did some rough measurements by adding -nographic -S to the command line, pressing 'Ctrl-A c' to get to the monitor, then 'Ctrl-A t' to turn on timestamps then typing 't' and finally Enter.

For standard BIOS until first kernel message this gave 0.989, 0.932, 0.988 (average: 0.969) For qboot BIOS (fw_cfg): 0.895, 0.887, 0.835 (average: 0.872)

so about 96ms saving. I haven't tried with cbfs yet.

(This is with a stock Ubuntu 14.10 qemu - not re-compiled to disable sundry features)

davedoesdev commented 9 years ago

cbfs timings: 0.688 0.597 0.643 (average: 0.642)

so another 230ms saving and 327ms over standard BIOS.

bonzini commented 9 years ago

I compiled qboot with -DBENCHMARK_HACK and added "-device isa-debug-exit,iobase=0xf4" to the QEMU command line. Then you can just us "time" from the shell.