OSDev.org

The Place to Start for Operating System Developers
It is currently Wed Apr 24, 2024 2:41 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 7 posts ] 
Author Message
 Post subject: Emulator for Mac OS X
PostPosted: Thu Jul 10, 2014 9:40 am 
Offline
Member
Member

Joined: Tue Dec 13, 2011 4:11 pm
Posts: 103
I just need a short rant, leading to a question: what emulator are you using for a 64-bit kernel for Mac OS X? And how did you install it? And most importantly: if qemu, how did you get it to work (on switching from protected mode to long mode)?

See, I started out using bochs (installed using macports). It was fine for my 32-bit kernel, but then I started building a 64 bit kernel... I just would have to specify that it should use a 64-bit processor. So, here we go: "cpuid: x86_64=1". "cpuid directive malformed." Just that. Well, **** you. I googled around for some working combinations (maybe I needed to specify some more settings for 64-bit support). Same error. The source code has if-statements to test for every condition, it just won't tell you which "if" statement decided something was wrong. Because, **** you.
I found out that bochs needed to be compiled using x86_64 support, and it probably wasn't (macports didn't specify the argument), so I tried to add it. "cpuid directive malformed." Just... **** you.
Okay, off with macports. I'll compile it myself. I download it, configure with some flags that look like I need them, make... Aaaand error about some type not being declared (cdrom_base). It recommends cdrom_base_c, so I add a typedef. Waaay more errors, that have nothing to do with the previous one. Great.
Off to google. Apparently there's a script that compiles it, especially for the mac! I run it, aaaand... **** you some more. We'll use a compiler flag that your compiler doesn't know. So, I try switching to gcc (non-cross compiling, installed using macports). More compiler flags that aren't recognised.
Screw bochs, time to give qemu a try.

First, qemu seems to work like a charm. 64-bit code runs fine. Until I place a breakpoint. See, qemu works fine, except in combination with gdb when you switch from protected mode to long mode. It will crash saying some message is too large.
Off to google. Some posts, on this forum as well. Apparently one can revert a commit from the stone ages, except that it won't work just reverting this one. I don't want to reset all the way back to such an old version either. Some comment of Brendan containing a patch he says works, but doesn't (it probably did back then, but after countless of updates, it doesn't seem to anymore). Some patch for gdb which looks like a terrible hack of some random guy on here. It may work, but I'm not sure I want to try it. Nobody commented it worked, anyway.

So, back to bochs. I manage to compile it manually, finally, using the absolutely minimum required flags:
Code:
CFLAGS="-I/opt/X11/include -L/opt/X11/lib" CXXFLAGS="-I/opt/X11/include -L/opt/X11/lib" ./configure --with-prefix=/usr/local --enable-gdb-stub --with-x11 --enable-x86-64

Well, that worked (it seems most of the issues came from it automatically using carbon). It finally seems to have x86-64 support now. I haven't tested anything else (I was actually typing this post waiting for it to compile a few times).

Still, bochs feels like a mess now. It's slow as hell anyway.

Anyways, so: which emulator are you using? Does anyone have a working qemu with gdb when switching from protected mode to long mode? One that isn't terribly old anyway, and how did you do it?


Top
 Profile  
 
 Post subject: Re: Emulator for Mac OS X
PostPosted: Thu Jul 10, 2014 10:21 am 
Offline
Member
Member
User avatar

Joined: Wed Dec 01, 2010 3:41 am
Posts: 1761
Location: Hong Kong
There is a trick to make qemu work with gdb to debug 64-bit kernel.

This is what I do:
1. start qemu in debug mode.
2. start gdb with remote session.
3. set breakpoint at kmain (64-bit code), continue
4. gdb complain on packet too long
5. set arch i386:x86-64
6. set arch i386:x86-64:intel
7. repeat 5, 6 a few times until gdb agree with your command.
(You should see a message like: The target architecture is assumed to be i386:x86-64)
8. info reg should shows 64-bit reg content now
9. happy debugging

By the way, I'm using macport's qemu and gdb 7.7 compiled from source


Top
 Profile  
 
 Post subject: Re: Emulator for Mac OS X
PostPosted: Thu Jul 10, 2014 11:29 am 
Offline
Member
Member

Joined: Tue Dec 13, 2011 4:11 pm
Posts: 103
Thanks for your answer!
First of all: turns out debugging in bochs doesn't work either. Not sure what's going on there, but I put that on halt to get back to qemu using your method.

Unfortunately, it doesn't work for me. Part of my code looks as follows:
Code:
   # Setup paging for long mode
   # ...

   # Setup the long mode gdt
   lgdt   gdt_long
   mov      $0x10, %ax
   mov      %ax, %ds
   mov      %ax, %es
   mov      %ax, %fs
   mov      %ax, %gs
   mov      %ax, %ss
   ljmp   $0x08, $.long_mode

.code64
.long_mode:
   jmp      kernel_main


The "kernel_main" code runs fine (prints some stuff to the terminal). So all looks good. However, I tried this (gdb 7.7.1, cross compiled, qemu from macports):
Code:
(gdb) file ../.bin/kernel
Reading symbols from ../.bin/kernel...done.
(gdb) b .long_mode
Breakpoint 1 at 0x100116: file bootstrap/boot.s, line 174.
(gdb) tar rem :1234
Remote debugging using :1234
0x0000fff0 in ?? ()
(gdb) c
Continuing.
Remote 'g' packet reply is too long: 10000080...801f0000
(gdb) info reg
Target is executing.
(gdb) set arch i386:x86-64
The target architecture is assumed to be i386:x86-64
(gdb) set arch i386:x86-64:intel
The target architecture is assumed to be i386:x86-64:intel

The break address seems to be correct. This is what objdump -d displays:
Code:
00100116 <.long_mode>:
  100116:   e9 e9 07 00 00          jmp    100904 <kernel_main>


The same "Target is executing." is displayed after running the set arch commands several times. Of course, I can't continue either:
Code:
(gdb) c
Continuing.
Cannot execute this command while the selected thread is running.


So nothing I can do except for killing the app, it seems. Without setting the breakpoint it does work fine, though. Until I press ctrl+c, that is:
Code:
^CRemote 'g' packet reply is too long: 00000000...1f0000
Remote 'g' packet reply is too long: 0000000...1f0000
Remote 'g' packet reply is too long: 000000...0801f0000
(gdb) info reg
../../gdb-7.7.1/gdb/findvar.c:292: internal-error: value_of_register_lazy: Assertion `frame_id_p (get_frame_id (frame))' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n)



I also tried this (where boot.s:116 is the long jump to long mode):
Code:
(gdb) b bootstrap/boot.s:116
Breakpoint 1 at 0x1000bc: file bootstrap/boot.s, line 116.
(gdb) tar rem :1234
Remote debugging using :1234
0x0000fff0 in ?? ()
(gdb) c
Continuing.

Breakpoint 1, .loop_page_table () at bootstrap/boot.s:116
116      ljmp   $0x08, $.long_mode
(gdb) b .long_mode
Breakpoint 2 at 0x100116: file bootstrap/boot.s, line 174.
(gdb) stepi
Remote 'g' packet reply is too long: 10000080...1f0000
(gdb) info reg
Target is executing.


Again, it's left in a state executing... And nothing I can do.

Also:
Code:
(gdb) b bootstrap/boot.s:116
Breakpoint 1 at 0x1000bc: file bootstrap/boot.s, line 116.
(gdb) tar rem :1234
Remote debugging using :1234
0x0000fff0 in ?? ()
(gdb) c
Continuing.

Breakpoint 1, .loop_page_table () at bootstrap/boot.s:116
116      ljmp   $0x08, $.long_mode
(gdb) info reg
eax            0x80000010   -2147483632
ecx            0xc0000080   -1073741696
edx            0x0   0
ebx            0x3001   12289
esp            0x3f8   0x3f8
ebp            0x67e5c   0x67e5c
esi            0x56bfa   355322
edi            0x1001   4097
eip            0x1000bc   0x1000bc <.loop_page_table+103>
eflags         0x86   [ PF SF ]
cs             0x8   8
ss             0x10   16
ds             0x10   16
es             0x10   16
fs             0x10   16
gs             0x10   16
(gdb) set arch i386:x86-64:intel
The target architecture is assumed to be i386:x86-64:intel
(gdb) info reg
(gdb) info reg
rax            0xc000008080000010   -4611685466524090352
rbx            0x300100000000   52780853100544
rcx            0x67e5c000003f8   1827783462355960
rdx            0x100100056bfa   17596481367034
rsi            0x86001000bc   575526666428
rdi            0x1000000008   68719476744
rbp            0x1000000010   0x1000000010
rsp            0x1000000010   0x1000000010
r8             0x0   0
r9             0x0   0
r10            0x0   0
r11            0x0   0
r12            0x0   0
r13            0x0   0
r14            0x0   0
r15            0x0   0
rip            0x0   0x0
eflags         0x0   [ ]
cs             0x0   0
ss             0x37f   895
ds             0x0   0
es             0x0   0
fs             0x0   0
gs             0x0   0


So, all the registers are messed up...

Any idea on how to fix this?


Thanks!

Edit: fixed the too long lines.
Edit2: Actually, after breaking with Ctrl+C I could change the arch, and the registers seem correct there... The RIP is as I expected, so the only issue with this solution seems to be the fact the breakpoint won't trigger (at least, not anything other than an error)... Any ideas?


Top
 Profile  
 
 Post subject: Re: Emulator for Mac OS X
PostPosted: Thu Jul 10, 2014 8:37 pm 
Offline
Member
Member
User avatar

Joined: Wed Dec 01, 2010 3:41 am
Posts: 1761
Location: Hong Kong
Well, if "b kmain" mess things up (gdb sometime thinks the thread is still running since it failed to get debug info), you may try this:

1. start qemu with debug mode
2. start gdb remote session
3. continue, and quickly press ctrl-c after entered 64-bit
4. set arch
5. b XXX
6. continue

My log:
Code:
$ ./gdb64.sh
GNU gdb (GDB) 7.7
Copyright (C) 2014 Free Software Foundation, Inc.
...
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ../usr/bin/x86_64/kernel64.sym...done.
0x0000fff0 in ?? ()
(gdb) c
Continuing.
^CRemote 'g' packet reply is too long: dd880b80ffffffff38711080ffffffff3a00000100000000650000000000000040420f00000000005300000000000000cdcccccccccccccc888b1280ffffffff00000000000000003a00000100000000c8ffbf7f0000000040801080ffffffff38711080ffffffff20040001000000000000000000000000000000000000000008131080ffffffff8302000008000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000801f0000
Remote 'g' packet reply is too long: dd880b80ffffffff38711080ffffffff3a00000100000000650000000000000040420f00000000005300000000000000cdcccccccccccccc888b1280ffffffff00000000000000003a00000100000000c8ffbf7f0000000040801080ffffffff38711080ffffffff20040001000000000000000000000000000000000000000008131080ffffffff8302000008000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000801f0000
Remote 'g' packet reply is too long: dd880b80ffffffff38711080ffffffff3a00000100000000650000000000000040420f00000000005300000000000000cdcccccccccccccc888b1280ffffffff00000000000000003a00000100000000c8ffbf7f0000000040801080ffffffff38711080ffffffff20040001000000000000000000000000000000000000000008131080ffffffff8302000008000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000801f0000
(gdb) set arch i386:x86-64
The target architecture is assumed to be i386:x86-64
(gdb) b kprintf
Breakpoint 1 at 0xffffffff801015c0
(gdb) c
Continuing.

Breakpoint 1, 0xffffffff801015c0 in kprintf ()
(gdb)


Top
 Profile  
 
 Post subject: Re: Emulator for Mac OS X
PostPosted: Fri Jul 11, 2014 2:31 am 
Offline
Member
Member

Joined: Tue Dec 13, 2011 4:11 pm
Posts: 103
Thanks for your reply!

While that works, I don't really want to leave it at that though. I simply want to be able to debug from eclipse, yet I can't this way.

Reading the source, the patch suggested in an earlier topic doesn't sound so bad anymore. It seems to have the right idea (even though it's hackey), so it could work...

I'll try that soon (probably not today), and I'll update here when I've tried *crossing fingers*. If anybody has any other method, I'm open to alternatives!


Top
 Profile  
 
 Post subject: Re: Emulator for Mac OS X
PostPosted: Fri Jul 11, 2014 3:21 am 
Offline
Member
Member
User avatar

Joined: Tue Dec 27, 2011 7:57 am
Posts: 368
See, there's another solution.
http://brew.sh

While macports does seem to have a larger range of packages, homebrew just seems to work better for me. I installed bochs using 'brew install bochs', no problems getting it to work. 64-bit, debugging etc - bochs works.

Not saying that my OS works on bochs, of course :p

_________________
[nx] kernel: http://github.com/zhiayang/nx


Top
 Profile  
 
 Post subject: Re: Emulator for Mac OS X
PostPosted: Fri Jul 11, 2014 2:23 pm 
Offline
Member
Member

Joined: Tue Dec 13, 2011 4:11 pm
Posts: 103
Thanks for your answers, all.

I actually - somehow - managed to get this working with qemu. Eclipse can now successfully debug my 64-bit kernel (after a protected-mode to long-mode transition). My fix was based on the hack-fix of z0rr0 as seen in the thread: http://forum.osdev.org/viewtopic.php?f=13&p=177644 even though this wasn't enough for me (though my hack-fix is only one line longer).

Disclaimer: this fix is terrible, disgusting, and unacceptable. It should not be used by anyone. Even by me. But hey, at least it works. IF you were to use it, make sure you use a completely new gdb copy just for this purpose.

First, we need a modification in gdb, in gdb/remote.c. Replace the following lines:
Code:
  if (buf_len > 2 * rsa->sizeof_g_packet)
    error (_("Remote 'g' packet reply is too long: %s"), rs->buf);


With:
Code:
  // HACKFIX for changing architectures for qemu. It's ugly. Don't use, unless you have to.
  // Just a tiny modification of the patch of Matias Vara (http://forum.osdev.org/viewtopic.php?f=13&p=177644)
  if (buf_len > 2 * rsa->sizeof_g_packet)
    {
      rsa->sizeof_g_packet = buf_len ;

      for (i = 0; i < gdbarch_num_regs (gdbarch); i++)
        {
          if (rsa->regs[i].pnum == -1)
            continue;

          if (rsa->regs[i].offset >= rsa->sizeof_g_packet)
            rsa->regs[i].in_g_packet = 0;
          else
            rsa->regs[i].in_g_packet = 1;
        }

      // HACKFIX: Make sure at least the lower half of EIP is set correctly, so the proper
      // breakpoint is recognized (and triggered).
      rsa->regs[8].offset = 16*8;
    }


The last line (with the offset, with all the lovely magic constants) is mine. The rest of the patch worked, except that the breakpoint wasn't recognised by gdb, as eip wasn't set properly. This hack fix should set the eip register (at index 8 ) to the least significant bytes of rip (which happens to be at 16*8 - the 16th index, 8 bytes per register).
So, now gdb will both break on the 64-bit mode breakpoint, and also (importantly, for me): recognise the proper breakpoint. Now we can automatically execute a command to fix the issue when long mode is entered. Here, .long_mode is the label that is the target of the ljmp that jumps into long mode. Enter this in gdb (perhaps use .gdbinit, or "source file"):
Code:
b .long_mode
command
set arch i386:x86-64
c
end


Whenever .long_mode is hit, it will set the architecture to i386:x86-64 and continue. Any other breakpoint should now work properly.

Phew, that was terrible. But at least it works now.


Thanks for your help, guys!


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 7 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: JustVic and 192 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group