MINIX 3.1.6 works in QEMU-0.12.3 only with KVM disabled
A message that is not in the archive (sent off-list or not yet received): [email protected]
Avi Kivity wrote on 2010-03-10 13:03:25 +0200:
Quoted 15 lines · Erik van der Kouwe
Quoted 2 lines
I've submitted this bug report a week ago:
http://sourceforge.net/tracker/?func=detail&aid=2962575&group_id=180599&atid=893831MINIX is using big real mode which is currently not well supported by kvm on Intel hardware:
Quoted 8 lines
(qemu) info registers
EAX=00000010 EBX=00000009 ECX=49200000 EDX=0000a796 ESI=00000200 EDI=49200200 EBP=00000009 ESP=0000a762 EIP=0000f4a7 EFL=00023002 [-------] CPL=3 II=0 A20=1 SMM=0 HLT=0 ES =0000 000000000000ffff0000f300
CS =f000000f00000000ffff0000f300
SS =9492 000949200000ffff0000f300
DS =97ce00097cec0000ffff0000f300
Quoted 4 lines
A ds.base of
0x97ceccannot be translated to a real mode segment.There is some work to get this to work, but it is proceeding really slowly. It should work on AMD hardware though.
Hi guys,
I searched the issue, and Erik was kind enough to point me to this list where there are knowledgeable people.
Erik van der Kouwe wrote in
http://groups.google.com/group/minix3/msg/40f44df0c434cfa6:
Quoted 7 lines
The situation is as follows:
The boot monitor runs in real-address mode, but has to copy parts of the boot image into high memory (>= 1 MB) which is not accessible from that mode as only 20 bits are available. It calls the BIOS (int
0x15) to perform the copy. This is done under theext_copylabel in boot/ boothead.s.
Okay. It is my understanding this is where Minix' involvement stops.
Quoted 4 lines
The BIOS switches to protected mode, loading a GDT which it receives from the caller. Before returning to the caller, it copies data using the segment descriptors in the GDT and switches back to real-address mode.
This is the description of BIOS service 15/87, which have to be implemented (using whatever solution it pleases) by the BIOS.
Quoted 3 lines
When doing switch, the cached segment selectors are preserved, which allows one to use protected mode segments in real-address mode (this is called unreal mode).
Now this is a by-product of the implementation inside the BIOS. In fact, even if the BIOS enters unreal mode (or the similar big real, more useful with segmentation-less architectures), before turning back to the client it (should) reset things to normal real mode, as service 15/87 is not an usual way to enter unreal mode (for example, this effect is not even mentionned in Ralf Brown's list).
As a result (and also and foremost because of 80286 compatibility), instead of directly using unreal or big real mode if possible (as done eg. in himem.sys), Minix monitor goes to the great pain to going back to square #1, and since blocks are at most 64 KB in size and several iterations are needed, on the next block Minix sets up the (very similar) GDT then does another call to the same BIOS service 15/87.
Quoted 3 lines
I knew these parts before, but this is where Avi's answer came in: KVM on Intel does not yet support unreal mode and requires the cached segment descriptors to be valid in real-address mode.
I do not know which virtual BIOS is using KVM, but I notice while reading http://bochs.sourceforge.net/cgi-bin/lxr/source/bios/rombios.c:
[ Slightly edited to fit the width of my post. AL. ]
3555 case 0x87:
3556 #if BX_CPU < 3
3557 # error "Int15 function 87h not supported on < 80386" 3558 #endif
3559 // +++ should probably have descriptor checks
3560 // +++ should have exception handlers
...
3640 mov eax, cr0 3641 or al, #0x01 3642 mov cr0, eax 3643 ;; far jump to flush CPU queue after transition to prot. mode 3644 JMP_AP(0x0020, protected_mode) 3645 3646 protected_mode: 3647 ;; GDT points to valid descriptor table, now load SS, DS, ES 3648 mov ax, #0x28 ;; 101 000 = 5th desc.in table, TI=GDT,RPL=00 3649 mov ss, ax 3650 mov ax, #0x10 ;; 010 000 = 2nd desc.in table, TI=GDT,RPL=00 3651 mov ds, ax 3652 mov ax, #0x18 ;; 011 000 = 3rd desc.in table, TI=GDT,RPL=00 3653 mov es, ax 3654 xor si, si 3655 xor di, di 3656 cld 3657 rep 3658 movsw ;; move CX words from DS:SI to ES:DI 3659 3660 ;; make sure DS and ES limits are 64KB 3661 mov ax, #0x28 3662 mov ds, ax 3663 mov es, ax 3664 3665 ;; reset PG bit in CR0 ??? 3666 mov eax, cr0 3667 and al, #0xFE 3668 mov cr0, eax
I should be loosing something here... There is no unreal mode at any moment, is it?
[ ... some web browsing occuring meanwhile ... Later: ]
Okay, now I got another picture. 8-|
Until recently, KVM (and qemu) used Bochs BIOS, showed above; but they switched recently to SeaBIOS... where the applicable code is in src/system.c, and looks like (now this is AT&T assembly):
83 static void
84 handle_1587(struct bregs *regs)
85 {
86 // +++ should probably have descriptor checks
87 // +++ should have exception handlers
....
127 // Enable protected mode 128 " movl %%cr0, %%eax\n" 129 " orl $" __stringify(CR0_PE) ", %%eax\n" 130 " movl %%eax, %%cr0\n" 131 132 // far jump to flush CPU queue after transition to prot. mode 133 " ljmpw $(4<<3), $1f\n" 134 135 // GDT points to valid descriptor table, now load DS, ES 136 "1:movw $(2<<3), %%ax\n" // 2nd descriptor in table, TI=GDT, RPL=00 137 " movw %%ax, %%ds\n" 138 " movw $(3<<3), %%ax\n" // 3rd descriptor in table, TI=GDT, RPL=00 139 " movw %%ax, %%es\n" 140 141 // move CX words from DS:SI to ES:DI 142 " xorw %%si, %%si\n" 143 " xorw %%di, %%di\n" 144 " rep movsw\n" 145 146 // Disable protected mode 147 " movl %%cr0, %%eax\n" 148 " andl $~" __stringify(CR0_PE) ", %%eax\n" 149 " movl %%eax, %%cr0\n"
Note that while the basic scheme is the same, the "cleaning up" of lines 3660-3663 "make sure DS and ES limits are 64KB" is not present. IIUC, the virtualized CPU goes back to real mode with those segments sets as they are in protected mode, and yes with Minix boot monitor they happenned to NOT be paragraph-aligned.
Is it possible to add back this "cleaning up" to the BIOS used in KVM?
Antoine
Quoted 5 lines · Antoine Leca
Quoted 5 lines
When doing switch, the cached segment selectors are preserved, which allows one to use protected mode segments in real-address mode (this is called unreal mode).
Quoted 7 lines
Now this is a by-product of the implementation inside the BIOS. In fact, even if the BIOS enters unreal mode (or the similar big real, more useful with segmentation-less architectures), before turning back to the client it (should) reset things to normal real mode, as service 15/87 is not an usual way to enter unreal mode (for example, this effect is not even mentionned in Ralf Brown's list).
The entry into unreal mode is unintentional; the bios is transitioning to protected mode and 'unreal mode' only exists for a few instructions, IIRC.
Quoted 94 lines
As a result (and also and foremost because of 80286 compatibility), instead of directly using unreal or big real mode if possible (as done eg. in himem.sys), Minix monitor goes to the great pain to going back to square #1, and since blocks are at most 64 KB in size and several iterations are needed, on the next block Minix sets up the (very similar) GDT then does another call to the same BIOS service 15/87.
Quoted 4 lines
I knew these parts before, but this is where Avi's answer came in: KVM on Intel does not yet support unreal mode and requires the cached segment descriptors to be valid in real-address mode.
I do not know which virtual BIOS is using KVM, but I notice while reading http://bochs.sourceforge.net/cgi-bin/lxr/source/bios/rombios.c:
[ Slightly edited to fit the width of my post. AL. ]
3555 case0x87:
3556 #if BX_CPU< 3
3557 # error "Int15 function 87h not supported on< 80386" 3558 #endif
3559 // +++ should probably have descriptor checks
3560 // +++ should have exception handlers
...3640 mov eax, cr0 3641 or al, #0x01 3642 mov cr0, eax 3643 ;; far jump to flush CPU queue after transition to prot. mode 3644 JMP_AP(0x0020, protected_mode) 3645 3646 protected_mode: 3647 ;; GDT points to valid descriptor table, now load SS, DS, ES 3648 mov ax, #0x28 ;; 101 000 = 5th desc.in table, TI=GDT,RPL=00 3649 mov ss, ax 3650 mov ax, #0x10 ;; 010 000 = 2nd desc.in table, TI=GDT,RPL=00 3651 mov ds, ax 3652 mov ax, #0x18 ;; 011 000 = 3rd desc.in table, TI=GDT,RPL=00 3653 mov es, ax 3654 xor si, si 3655 xor di, di 3656 cld 3657 rep 3658 movsw ;; move CX words from DS:SI to ES:DI 3659 3660 ;; make sure DS and ES limits are 64KB 3661 mov ax, #0x28 3662 mov ds, ax 3663 mov es, ax 3664 3665 ;; reset PG bit in CR0 ??? 3666 mov eax, cr0 3667 and al, #0xFE 3668 mov cr0, eaxI should be loosing something here... There is no unreal mode at any moment, is it?
[ ... some web browsing occuring meanwhile ... Later: ]
Okay, now I got another picture. 8-|
Until recently, KVM (and qemu) used Bochs BIOS, showed above; but they switched recently to SeaBIOS... where the applicable code is insrc/system.c, and looks like (now this is AT&T assembly):
83 static void
84handle_1587(struct bregs *regs)
85 {
86 // +++ should probably have descriptor checks
87 // +++ should have exception handlers
....127 // Enable protected mode 128 " movl %%cr0, %%eax\n" 129 " orl $" __stringify(CR0_PE) ", %%eax\n" 130 " movl %%eax, %%cr0\n" 131 132 // far jump to flush CPU queue after transition to prot. mode 133 " ljmpw $(4<<3), $1f\n" 134 135 // GDT points to valid descriptor table, now load DS, ES 136 "1:movw $(2<<3), %%ax\n" // 2nd descriptor in table, TI=GDT, RPL=00 137 " movw %%ax, %%ds\n" 138 " movw $(3<<3), %%ax\n" // 3rd descriptor in table, TI=GDT, RPL=00 139 " movw %%ax, %%es\n" 140 141 // move CX words from DS:SI to ES:DI 142 " xorw %%si, %%si\n" 143 " xorw %%di, %%di\n" 144 " rep movsw\n" 145 146 // Disable protected mode 147 " movl %%cr0, %%eax\n" 148 " andl $~" __stringify(CR0_PE) ", %%eax\n" 149 " movl %%eax, %%cr0\n"
Quoted 9 lines
Note that while the basic scheme is the same, the "cleaning up" of lines 3660-3663 "make sure DS and ES limits are 64KB" is not present. IIUC, the virtualized CPU goes back to real mode with those segments sets as they are in protected mode, and yes with Minix boot monitor they happenned to NOT be paragraph-aligned.
Is it possible to add back this "cleaning up" to the BIOS used in KVM?
I think so. This is a longstanding kvm bug, but I can't see any downsides to a workaround in the BIOS.
Signature · 1 line
error compiling committee.c: too many arguments to function