Do uruchomienia UML potrzebujemy dwóch jąder:
UML korzysta z jądra systemu tylko do emulowania wirtualnego sprzetu.
UML działa w dwóch trybach: TT i SKAS.
Historycznie pterwszym był tryb TT. Tryb SKAS powstał w celu usunięcia problemów związanych z trybem TT
Problemy związane z trybem TT:
Jądra mają oddzielną przestrzeń adresową.
Aby uruchomić UML w trybie SKAS należy zainstalować łatę na jądro gospodarza.
Łata ta implementuje wsparcie dla przestrzeni adresowej używanej przez UML, oraz kilka niezbędnych dodatków dla ptrace
W trybie SKAS z poziomu gospodarza widoczne są tylko 4 procesy:
Gotowy system plików do ściągnięcia,
wraz z jądrem można znaleźć np. na
http://user-mode-linux.sourceforge.net/
Na tej samej stronie znajduje się również sposób uruchomienia UML.
Niestety w takuruchomionym UML nie da się śledzić procesów jądra.
host% wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.16.tar.bz2i je rozpakować. W naszym wypadku:
host% bunzip2 linux-2.6.16.tar.bz2 host% tar xf linux-2.6.16.tar host% cd linux-2.6.16
host% make defconfig ARCH=um host% make menuconfig ARCH=umAby móc używiać gdb, w celu odpluskiania jądra musimy ustawić flagi CONFIG_DEBUG_INFO oraz CONFIG_FRAME_POINTER.
host% make ARCH=um
host% ./linux
Przydatnym narzędziem do zarządzania UML jest Management Console.
Jest to niskopoziomowy interfejs do jądra.
Dzięki MConsole można m.in.:
pełna lista instrukcji i sposobów ich wywołania znajduje się na: http://user-mode-linux.sourceforge.net/old/mconsole.html
aby uruchomić MConsole należy uruchomić UML-a z opcją
umid=identyfikator
A następnie uruchomić MConsole poleceniem:
host% uml_mconsole identyfikator
W łatwy sposób można w UML tworzyc i dołączać nowe systemy plików:
UML udostępnia pliki typu COW (copy-on-write).
Umożliwiają one współdzielenie systemu plików między maszynami
wirtualnymi.
IDEA: Współdzielony system pliku służy tylko do odczytu.
Wszelkie zmiany przechowywane są przez każdą z maszyn z osobna.
Maszyny czytają najświeższe posiadane przez siebie zawartości plików
Dokładniejsze informacje można uzyskać na stronie: http://user-mode-linux.sourceforge.net/old/shared_fs.html
Aby móc śledzić działanie jądra należy zbudować UML ze źródła.
Dla tak zbudowanego UML-a można używać gdb,
jak dla każdego innego procesu:
% gdb obj/linux GNU gdb Red Hat Linux (6.3.0.0-1.122rh) Copyright 2004 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1". (gdb) b start_kernel Breakpoint 1 at 0x80493c3: file /home/jdike/linux/2.6/test/linux-2.6.17/init/main.c, line 461. (gdb) r Starting program: /home/jdike/linux/2.6/test/linux-2.6.17/obj/linux Reading symbols from shared object read from target memory...done. Loaded system supplied DSO at 0x615000 Detaching after fork from child process 24108. Checking that ptrace can change system call numbers...OK Detaching after fork from child process 24109. Checking syscall emulation patch for ptrace...OK Detaching after fork from child process 24110. Checking advanced syscall emulation patch for ptrace...OK Checking for tmpfs mount on /dev/shm...OK Checking PROT_EXEC mmap in /dev/shm/...OK Checking for the skas3 patch in the host: - /proc/mm...not found Detaching after fork from child process 24111. - PTRACE_FAULTINFO...not found Detaching after fork from child process 24112. - PTRACE_LDT...not found UML running in SKAS0 mode Adding 25427968 bytes to physical memory to account for exec-shield gap Breakpoint 1, start_kernel () at /home/jdike/linux/2.6/test/linux-2.6.17/init/main.c:461 461 smp_setup_processor_id(); (gdb) n 469 local_irq_disable(); (gdb)
Czasami UML pomija breakpoint'y ustawione w gdb (błąd gdb (?)). http://user-mode-linux.sourceforge.net proponuje 2 rozwiązania tego problemu:
gdb ./linux `cat ~/.uml/UMID/pid`
Przy użyciu UML możemy także śledzić działanie poszczególnych modułów
Najpierw dodajemy moduł do UML-a:
Następnie musimy zlokalizować, gdzie w pamięci znajduje się moduł:
(gdb) p modules $1 = {next = 0x3502cea4, prev = 0x3502cea4}Od wartości next odejmujemy 4 i wywołujemy:
(gdb) p *((struct module *)0x3502cea0) $3 = {state = MODULE_STATE_LIVE, list = {next = 0x81e0dec, prev = 0x81e0dec}, name = "loop", '\0' <repeats 55 times>, mkobj = {kobj = { k_name = 0x3502ceec "loop", name = "loop", '\0' <repeats 15 times>, kref = {refcount = {counter = 2}}, entry = {next = 0x81e0ac8, prev = 0x34a486c8}, parent = 0x81e0ad0, kset = 0x81e0ac0, ktype = 0x0, dentry = 0x3297277c, poll = {lock = {raw_lock = {<No data fields>}}, task_list = {next = 0x3502cf1c, prev = 0x3502cf1c}}}, mod = 0x3502cea0}, param_attrs = 0x0, modinfo_attrs = 0x9598620, version = 0x0, srcversion = 0x0, syms = 0x3502bc20, num_syms = 2, crcs = 0x0, gpl_syms = 0x0, num_gpl_syms = 0, gpl_crcs = 0x0, unused_syms = 0x0, num_unused_syms = 0, unused_crcs = 0x0, unused_gpl_syms = 0x0, num_unused_gpl_syms = 0, unused_gpl_crcs = 0x0, gpl_future_syms = 0x0, num_gpl_future_syms = 0, gpl_future_crcs = 0x0, num_exentries = 0, extable = 0x0, init = 0x3502f000, module_init = 0x0, module_core = 0x3502a000, init_size = 0, core_size = 12328, init_text_size = 0, core_text_size = 6468, unwind_info = 0x0, arch = {<No data fields>}, unsafe = 0, license_gplok = 1, ref = {{count = { counter = 0}}}, modules_which_use_me = {next = 0x3502cfe0, prev = 0x3502cfe0}, waiter = 0x94cf7c0, exit = 0x3502b8b6, symtab = 0x3502bc30, num_symtab = 166, strtab = 0x3502c690 "", sect_attrs = 0x346e14d8, percpu = 0x0, args = 0x94c3698 ""}
(gdb) b loop_init Breakpoint 1 at 0x3502a009: file /home/jdike/linux/2.6/linux-2.6.18-mm/drivers/block/loop.c, line 1242. (gdb) c Continuing. Breakpoint 1, loop_init () at /home/jdike/linux/2.6/linux-2.6.18-mm/drivers/block/loop.c:1242 1242 if (max_loop < 1 || max_loop > 256) { (gdb)