0

I'm working on a simple real-mode OS in c++. I can't figure out how to print strings, though. The following code works when it's in the bootloader, but not when it's in the kernel.

__asm__ __volatile__(".code16gcc \n");

__asm__ __volatile__ ("xor ax, ax\n");
__asm__ __volatile__ ("mov ds, ax\n");

__asm__ __volatile__("jmp main \n");

void printf(const char* str)
{
    while(*str)
    {
        __asm__ __volatile__("int 0x10" : : "a"(0x0e00 | *str), "b"(0x0007));
        ++str;
    }
}

void main(){
    printf("Hi!");
}

I'm sure it's because the ds register it set to 0, but the code is actually at 0x7E00 (that's where the bootloader puts it). I've tried setting ds to 0x7E0, which should cause it to load data correctly because 0x7E0 * 16 = 0x7E00, but it still doesn't work. It's probably just some silly mistake, but I would appreciate some help. If it matters, here is my bootloader code:

__asm__(".code16gcc \n");

void main(){    
    __asm__ __volatile__("mov al, 0x02 \n");
    __asm__ __volatile__("xor ah, ah \n");
    __asm__ __volatile__("int 0x10 \n");

    __asm__ __volatile__("xor ax, ax \n");
    __asm__ __volatile__("mov es, ax \n");
    __asm__ __volatile__("mov bx, 0x7E00 \n");
    __asm__ __volatile__("mov al, 0x03 \n");
    __asm__ __volatile__("mov ch, 0x00 \n");
    __asm__ __volatile__("mov cl, 0x02 \n");
    __asm__ __volatile__("mov dh, 0x00 \n");
    __asm__ __volatile__("mov ah, 0x02 \n");
    __asm__ __volatile__("int 0x13 \n");

    __asm__ __volatile__("jmp 0:0x7E00 \n");
}
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
programmer
  • 743
  • 4
  • 10
  • If you want instructions to be contiguous and in the right order, it's better and easier to put them all into a single multi-line inline-asm statement. Or even better, write your whole function in asm, because letting gcc emit a function prologue / epilogue is doing nothing for you. Also, gcc has a `-m16` option to target 16-bit x86 (still using the 32-bit ABI / calling convention, so many instructions need operand-size / address-size prefixes). But that's better than tricking the compiler by putting `.code16gcc` in an inline-asm statement. – Peter Cordes Feb 24 '18 at 19:58
  • What do you see when you run your kernel under a debugger? (e.g. BOCHS has a debugger built-in, so you can single-step bootloader / kernel code and examine registers). Probably also a good idea to look at disassembly of the kernel you produced by abusing gcc this way. – Peter Cordes Feb 24 '18 at 20:00
  • boot loader is in 16-bit mode , is your kernel in 16-bit mode or else? if it goes to 32-bit mode then you need the whole new printing function in that mode too. – nullqube Feb 24 '18 at 20:06
  • 1
    I have written an answer you may wish to read: https://stackoverflow.com/a/43565655/3857942 . That answer supplies a link to some code that demonstrates the possibility of writing a bootloader that runs in real mode(but requires a 386+ to run). That code is here: http://capp-sysware.com/misc/ircasm/gccboot-2stage/ – Michael Petch Feb 24 '18 at 20:32
  • You might want to look at OpenWatcom or even Alexey Frunze's Smaller C Compiler that he has use to write his own bootloaders: https://github.com/alexfru/SmallerC . They both can generate proper 16-bit code. – Michael Petch Feb 24 '18 at 20:34
  • And as a warning I say this is in my other answer `There are so many pitfalls in doing this that I recommend against it.` GCC and 16-bit code are not for the faint of heart, and you must know what you are doing. – Michael Petch Feb 24 '18 at 20:36
  • 1
    Is there a reason why you are writing a 16-bit kernel. Have you considered a 32-bit or 64-bit kernel, and your bootloader switces into the proper mode first. – Michael Petch Feb 24 '18 at 20:37

0 Answers0