Page 1 of 2

qemu not writing to even memory addresses in video memory

Posted: Thu May 18, 2017 1:53 pm
by dethboy
I have written code that successfully switches to 320x200 linear 256-color mode and writes to the screen. In bochs it functions perfectly but in qemu it is skipping every other pixel. I stepped through with gdb and movb 0x01, address is being executed for each address but every second address doesn't get overwritten. anybody have a clue as to why this might be happening?

Re: qemu not writing to even memory addresses in video memor

Posted: Thu May 18, 2017 1:55 pm
by Geri
vga or vesa?

Re: qemu not writing to even memory addresses in video memor

Posted: Thu May 18, 2017 1:57 pm
by dethboy
VGA

Re: qemu not writing to even memory addresses in video memor

Posted: Thu May 18, 2017 1:58 pm
by Geri
seems like a nice qemu internal error. can you strip the code down to a few lines, and execute it?

Re: qemu not writing to even memory addresses in video memor

Posted: Thu May 18, 2017 2:02 pm
by dethboy
What do you mean? I need the whole mode swtiching code.

Re: qemu not writing to even memory addresses in video memor

Posted: Thu May 18, 2017 2:04 pm
by Geri
you dont need protected mode. just do it in the boot loader. do not do anything else. lets see what happens.

Re: qemu not writing to even memory addresses in video memor

Posted: Thu May 18, 2017 2:07 pm
by dethboy
will have to write my own boot loader then :D

Re: qemu not writing to even memory addresses in video memor

Posted: Thu May 18, 2017 2:14 pm
by Geri
[BITS 16]
[ORG 0x7C00];

switch vga mode
fill algorithm goes here

TIMES 510-($-$$) DB 0
DW 0xAA55


nasm it, copy to disk drive 0th sector, boot it

Re: qemu not writing to even memory addresses in video memor

Posted: Thu May 18, 2017 2:17 pm
by alexfru
Uninitialized or clobbered register or variable?

Re: qemu not writing to even memory addresses in video memor

Posted: Thu May 18, 2017 2:38 pm
by Brendan
Hi,
dethboy wrote:I have written code that successfully switches to 320x200 linear 256-color mode and writes to the screen. In bochs it functions perfectly but in qemu it is skipping every other pixel. I stepped through with gdb and movb 0x01, address is being executed for each address but every second address doesn't get overwritten. anybody have a clue as to why this might be happening?
Without any code to give any kind of clue what might or might not be wrong; I'd assume that the bug is that your code to do video mode switching expects the video card to be 100% VGA compatible at the hardware (IO port) level (and not just at the "BIOS int 0x10" level).


Cheers,

Brendan

Re: qemu not writing to even memory addresses in video memor

Posted: Thu May 18, 2017 2:49 pm
by dethboy
here is the mode switching and writing to video memory

Code: Select all

void port_3c0_write(uint8_t index, uint8_t data) {
    inb(0x3da); // read to clear index/data status
    outb(0x3c0, index); //send index
    outb(0x3c0, data); //send index
}

uint8_t port_3c0_read(uint8_t index) {
    uint8_t retval;
    inb(0x3da); // read to clear index/data status
    outb(0x3c0, index); //send index
    retval = inb(0x3C1);
    inb(0x3da); // read to clear index/data status
    return retval;
}

void port_3c4_write(uint8_t index, uint8_t data) {
    outb(0x3c4, index);
    outb(0x3c5, data);
}

void port_3ce_write(uint8_t index, uint8_t data) {
    outb(0x3ce, index);
    outb(0x3cf, data);
}

void port_3d4_write(uint8_t index, uint8_t data) {
    outb(0x3d4, index);
    outb(0x3d5, data);
}

uint8_t port_3d4_read(uint8_t index) {
    outb(0x3d4, index);
    return inb(0x3d5);
}

void do_switch(void) {
// now let's try to switch to mode 13h 320x200x256 linear
    // dont know if the order makes a difference
    /*MISC*/
    outb(0x3c2, 0x63); //Miscellaneous Output Register
    
    /*sequencer*/
    port_3c4_write(0x00, 0x03); // ?
    port_3c4_write(0x01, 0x01); // clock mode register
    port_3c4_write(0x02, 0x05);
    port_3c4_write(0x03, 0x00); // character select
    port_3c4_write(0x04, 0x0e); // memory mode register
    
    // unlock the crtc regs
    uint8_t temp = port_3d4_read(0x03);
    port_3d4_write(0x03, temp | 80); // ors against f000 0000
    temp = port_3d4_read(0x11);
    port_3d4_write(0x11, temp & ~80); // ands against 0fff ffff
    
    /*CRTC*/
    port_3d4_write(0x00, 0x5f); // horizontal total
    port_3d4_write(0x01, 0x4f); // horizontal display enable end
    port_3d4_write(0x02, 0x50); // Horizontal Blank Start 
    port_3d4_write(0x03, 0x82); // horizontal blank end
    port_3d4_write(0x04, 0x54); // horizontal retrace start
    port_3d4_write(0x05, 0x80); // horizontal retrace end
    port_3d4_write(0x06, 0xbf); // horizontal vertical total
    port_3d4_write(0x07, 0x1f); // horizontal overflow register
    port_3d4_write(0x08, 0x00); // horizontal preset row scan
    port_3d4_write(0x09, 0x41); // maximum scan line
    port_3d4_write(0x0A, 0x00); // ?
    port_3d4_write(0x0B, 0x00); // ?
    port_3d4_write(0x0C, 0x00); // ?
    port_3d4_write(0x0D, 0x00); // ?
    port_3d4_write(0x0E, 0x00); // ?
    port_3d4_write(0x0F, 0x00); // ?
    port_3d4_write(0x10, 0x9c); // vertical retrace start
    port_3d4_write(0x11, 0x8e); // vertical retrace end vga_hardware page has 8e doesnt seem to make a difference
    port_3d4_write(0x12, 0x8f); // vertical display enable end
    port_3d4_write(0x13, 0x28); // logical width
    port_3d4_write(0x14, 0x40); // unsderline location
    port_3d4_write(0x15, 0x96); // vertical blank start
    port_3d4_write(0x16, 0xb9); // vertical blank end
    port_3d4_write(0x17, 0xa3); // mode control
    port_3d4_write(0x18, 0xff); // ?
    
    /*Graphics Controller*/
    port_3ce_write(0x00, 0x00); // ?
    port_3ce_write(0x01, 0x00); // ?
    port_3ce_write(0x02, 0x00); // ?
    port_3ce_write(0x03, 0x00); // ?
    port_3ce_write(0x04, 0x00); // ?
    port_3ce_write(0x05, 0x40); // mode register
    port_3ce_write(0x06, 0x05); // misc register
    port_3ce_write(0x07, 0x0f); // ?
    port_3ce_write(0x08, 0xff); // ?
    
    /*attribute controller*/
    port_3c0_write(0x00, 0x00); // ?
    port_3c0_write(0x01, 0x01); // ?
    port_3c0_write(0x02, 0x02); // ?
    port_3c0_write(0x03, 0x03); // ?
    port_3c0_write(0x04, 0x04); // ?
    port_3c0_write(0x05, 0x05); // ?
    port_3c0_write(0x06, 0x06); // ?
    port_3c0_write(0x07, 0x07); // ?
    port_3c0_write(0x08, 0x08); // ?
    port_3c0_write(0x09, 0x09); // ?
    port_3c0_write(0x0A, 0x0a); // ?
    port_3c0_write(0x0B, 0x0b); // ?
    port_3c0_write(0x0C, 0x0c); // ?
    port_3c0_write(0x0D, 0x0d); // ?
    port_3c0_write(0x0E, 0x0e); // ?
    port_3c0_write(0x0F, 0x0f); // ?
    port_3c0_write(0x10, 0x41); //mode control
    port_3c0_write(0x11, 0x00); //Overscan register
    port_3c0_write(0x12, 0x0f); //Color Plane Enable
    port_3c0_write(0x13, 0x00); //Horizontal panning
    port_3c0_write(0x14, 0x00); //color select
    
    // lock color palette
    inb(0x3da); // read to clear index/data status
    outb(0x3c0, 0x20); //send index, switches here everything turns to ffff
    
    video_ram = (uint8_t*) 0xa0000;
    
    while (video_ram < (uint8_t*) 0xAFA00) {
        *video_ram = (uint8_t) 0b00000001;
        video_ram++;
    }
}


Re: qemu not writing to even memory addresses in video memor

Posted: Thu May 18, 2017 3:02 pm
by Geri
forget all about those graphics controller port writes. just delete them out from the code totally. they will not work. do the bios interrupt to switch the mode.

Re: qemu not writing to even memory addresses in video memor

Posted: Fri May 19, 2017 12:21 am
by mallard
Brendan wrote: Without any code to give any kind of clue what might or might not be wrong; I'd assume that the bug is that your code to do video mode switching expects the video card to be 100% VGA compatible at the hardware (IO port) level (and not just at the "BIOS int 0x10" level).
Thankfully, that "expectation" is met by all current hardware and by QEMU's emulation.

The actual bug is that the "Map Mask" register (Sequencer register 0x02) is set incorrectly, only enabling planes 1 and 3 (value 0x05), it should be set to 0x0F to enable all planes. Clearly Bochs ignores this value in "Chain 4" mode, but QEMU doesn't (QEMU is likely more accurate to real hardware).

Switching modes by writing the registers absolutely does work when done correctly on every emulator and hardware that I've tried. If you have any problems with the VGA registers or anything not working as you expect, I'd strongly recommend this documentation. Far better than the very incomplete and often misleading "documentation" in the wiki.

Re: qemu not writing to even memory addresses in video memor

Posted: Fri May 19, 2017 4:27 am
by dozniak
Did you probably masked some plane registers inadvertently? Afaik even in this mode you need to enable planes writing to be able to ... actually write to them.

Re: qemu not writing to even memory addresses in video memor

Posted: Fri May 19, 2017 7:10 am
by dethboy
mallard wrote: The actual bug is that the "Map Mask" register (Sequencer register 0x02) is set incorrectly, only enabling planes 1 and 3 (value 0x05), it should be set to 0x0F to enable all planes. Clearly Bochs ignores this value in "Chain 4" mode, but QEMU doesn't (QEMU is likely more accurate to real hardware).
it worked! I went back to the place where got the register settings from and it was indeed an 0x0F. I specifically re-checked many times and it still got past me.

Is there any protocol regarding updatating the wiki?