Sziasztok!
Egy `qemu-system-valami` rendszernek hogyan is tudom megmondani hogy hany (fizikainak latszo) soros portot adjon a guest-nek? Sima 8250/16550-es az tokeletes, a kernel az olyan hogy 4-et tud kezelni. De hiaba mondom hogy -serial /dev/ttyUSBx -serial /dev/ttySy -serial /dev/tntN ... valahogy mindig csak egy van... a fun az hogy lat 4 darab /dev/ttyS*-ot (0...3), a dmesg-ben is:
[ ... ]
[ 0.248096] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
[ ... ]
#
~ # ls -l /dev/ttyS*
crw------- 1 0 0 4, 64 Jan 1 00:00 /dev/ttyS0
crw------- 1 0 0 4, 65 Jan 1 00:00 /dev/ttyS1
crw------- 1 0 0 4, 66 Jan 1 00:00 /dev/ttyS2
crw------- 1 0 0 4, 67 Jan 1 00:00 /dev/ttyS3
de az elso kivetelevel azokra mind Input/output error-t mond barmi. A kernel az `nr_uarts=4` modon lett inditva...
Mondjuk a dmesg ezen kivul annyit mond hogy a /dev/ttyS0 az a konzol maga:
[ 0.250427] printk: console [ttyS0] disabled
[ 0.251717] 10000000.serial: ttyS0 at MMIO 0x10000000 (irq = 1, base_baud = 230400) is a 16550A
[ 0.287735] printk: console [ttyS0] enabled
ami valoban igy is van (a host oldalon latszik is szepen) de fentebb ez a "Serial: 8250/16550 driver, 4 ports" jonak tunik...
thx, A.
- 494 megtekintés
Hozzászólások
https://www.qemu.org/docs/master/
https://www.qemu.org/docs/master/specs/pci-serial.html
"-device pci-serial-4x"
- A hozzászóláshoz be kell jelentkezni
Nem segit sajnos, es nincs is PCI:
# CONFIG_PCI is not set
szerk: mondjuk ami gyanus hogy az i/o access az lehet byte, halfword meg word is 32 bites architektura eseten, es lehet hogy az offset-tel van a baj itten valami miatt.
- A hozzászóláshoz be kell jelentkezni
Akkor lehet, az lesz a baj. Esélyes, hogy egynél többhöz PCI kell, és az első csak azért működik, mert emulálva van a guest BIOS-bában, hogy ISA-ként is látszódjon. Ha van kedved ezzel szívni, compatmon0-ra kapcsolva (Ctrl+Alt+2) a qemu debugger-el kérd le az eszközlistát ("info devices" vagy valami ilyesmi), és akkor az is látszani fog pontosan, miként vannak leképezve a soros portok a guest-ben (jó eséllyel nem ISA). Na, amit ott látsz, ahhoz való kernel driverre lesz szükséged a guest OS-ben. Alapból a ttyS0-ttyS3 a sima ISA meghajtót használja, az 0x3F8, 0x2F8, 0x3E8, 0x2E8 IO portokon. Ha ezeken a portokon nincs semmi emulálva, akkor mindig hibát fogsz kapni a kernel drivertől. Az, hogy a guest dmesg-edben MMIO látszik, és nem is IO port, több, mint gyanús, hogy ez lesz a helyzet. A másik meg, az a 230400 baud, na a valódi 16550A csip sosem tudott ennyit (a maximuma 115200 Hz), ez is valami nagyon félrekonfolt dologra utal.
(Nekem egyébként szokott működni, hogy több -serial kapcsolót adok meg a qemu-nak, igaz, kettőnél többel még sose próbálkoztam.)
- A hozzászóláshoz be kell jelentkezni
Igen, ez egy RISC-V alapu rendszer (RV32IMAC_Zicsr, pontosabban szolva), szoval a legegyszerubb RV32-es architektura amire mar lehet ertelmes RTOS-t es/vagy Linuxot huzni. Szoval I/O port nincs (a CSR-ek nem arra valoak), csak MMIO van. Es mivel MMIO van, ezert jo kerdes hogy hogyan a leghatekonyabb 8x1 byte-ot lemappelni. Az "early console" forraskodjaban meg busy wait alapu az MMIO, es annak a forraskodjabol (ld: ./linuxdrivers/tty/serial/8250/8250_early.c) latszik hogy tobbfele I/O modozat kozul lehet valasztani. Ugyanakkor egy nativ 32+32 bites (ILP32-es) hardver a leghatekonyabban ezt nem byte-szinten hanem word-szinten fogja kezelni - szoval az teljesen termeszetes hogy itt lehet egy address space szethuzas. Es mivel van erre boven hely, ezert ez nem gond.
("info devices" vagy valami ilyesmi)
Aha, igen, egy ilyet talaltam:
QEMU 7.2.9 monitor - type 'help' for more information
(qemu) info chardev
serial1: filename=serial
parallel0: filename=null
compat_monitor0: filename=stdio
serial0: filename=serial
Itt megjelenik az a ket chardev amit megadtam:
$ qemu-system-riscv32 -m 512M -nographic -machine virt \
-kernel ./Image2 \
-initrd ./initramfs.cpio.gz \
-device pci-serial-4x \
-serial /dev/tnt0 \
-serial /dev/tnt2 \
-append "console=ttyS0 nr_uarts=4"
A /dev/tnt{0,1} paron ott van a konzol, be tudok lepni a Linuxra, minden oke. De a /dev/ttyS1-et (vagy barmelyik 0< soros portot) nem tudom elerni. Szoval jo lenne valami MMIO mappingot latni :)
- A hozzászóláshoz be kell jelentkezni
De a /dev/ttyS1-et (vagy barmelyik 0< soros portot) nem tudom elerni
Ahogy máshol írom a topikban, ez amiatt van, mert a riscv32 system emulator "virt" board-ja (más szóval "machine type"-ja) nem rendelkezik 1-nél több "alaplapi" soros porttal. Az érintett QEMU forrás a "hw/riscv/virt.c"; ebben az van, hogy
static const MemMapEntry virt_memmap[] = {
/* ... */
[VIRT_UART0] = { 0x10000000, 0x100 },
/* ... */
};
és a VIRT_UART0 az egyetlen ilyen.
Aztán lásd a forrásfile-ban a különféle hivatkozásokat a VIRT_UART0 makróra. Például a create_fdt_uart() függvény felelős azért, hogy az egyetlen soros portot megjelenítse a DTB-ben a guest számára. Valamint az egyetlen serial_mm_init() hívás a virt_machine_init() alaplap-inicializációs függvényben gondoskodik arról (többek között), hogy a guest-physical address space-ben a fent idézett MMIO tartománynak az egyetlen emulált soros port feleljen meg.
Ahogy máshol említem a thread-ben, az aarch64 system emulátor virt board-ja is hasonlóan nézett ki sokáig, de nemrég Peter Maydell megcsinálta ahhoz a második soros portot, én pedig az edk2-ben (= guest firmware) csináltam meg hozzá a guest firmware-beli támogatást:
https://bugzilla.tianocore.org/show_bug.cgi?id=4577
... Hoppá, várjunk csak! Most látom (teljesen meglepve), hogy Peter patch-ei nem is lettek a QEMU-ba beolvasztva! Ezt egyáltalán nem értem, mert én szénné teszteltem a feature-t. Mindjárt írok neki, hogy mi van.
- A hozzászóláshoz be kell jelentkezni
Én így használom, ( 1-nél többre sose volt szükség ):
-serial tcp:127.0.0.1:232,server,nowait,nodelay
Ezt berakod többször, csak a portot kell átírni, majd a host-ról a TCP portra kell csatlakozni ( pl.: telnet ).
USB soros átlakítót azt máshogyan kell átadni ( utána majd a guest-os betölti a drivert hozzá):
https://pve.proxmox.com/wiki/USB_Devices_in_Virtual_Machines
- A hozzászóláshoz be kell jelentkezni
Igen, koszi, ez a resze halistennek megy - haszaltam igy is soros port kihuzasat de most ez a /dev/tnt[01], [23], ... parositas nagyon hatekony (pl a QEMU leallitasa - ujrainditasa utan a masik fel nem szakad le, ilyesmi). Ezt a /dev/tnt* trukkot hasznalom mas (sajat) SoC emulatorokhoz is, ott is bevalt hasonlo okokbol. A TCP-s valtozat meg allando-fix telepites-uzemeltetes mellett hatekony :)
- A hozzászóláshoz be kell jelentkezni
Első probléma, hogy a soros portok száma az emulált board-tól (machine type-tól) függ. Például a "qemu-system-aarch64 -M virt" nem is olyan régen kapott támogatást a 2. soros porthoz; azt megelőzően csak 1 volt neki. Tehát ha az adott board nem támogat 1-nél több soros portot, akkor akármennyit megadhatsz a parancssorban, nem fog menni.
A modern szintaxis pedig az, hogy
-serial chardev:ser0 \
-serial chardev:ser1 \
-serial chardev:ser2 \
-serial chardev:ser2 \
-chardev serial,id=ser0,path=/dev/ttyS0 \
-chardev serial,id=ser1,path=/dev/ttyS1 \
-chardev serial,id=ser2,mux=on,path=/dev/ttyUSB0
Az első négy opció a frontend konfig (amit a guest lát).
A második három opció a backend konfig (ami a host-on történik).
A fenti példában a guest-nek négy soros portot adunk. Ebből az első kettő két különböző backend-re hivatkozik (ser0 és ser1 azonosítójú backend-ekkel), mely utóbbiak rendre a host /dev/ttyS0 és /dev/ttyS1 device-aihoz vannak kötve. Az utolsó kettő frontend (vagyis guest-side serial port) pedig osztozik a host oldalon a /dev/ttyUSB0 device-on, és hogy éppen melyik van vele összekötve, azt a "Ctrl-a c" kombinációval lehet váltogatni a /dev/ttyUSB0 felől. (Vagyis ha az éppen aktív frontend felé beviszel egy "Ctrl-a c"-t a backend felől, akkor a frontend nem fogja megkapni, hanem a következő frontend aktiválódik.)
- A hozzászóláshoz be kell jelentkezni
Oh, koszi, lehet hogy akkor ez lesz :/ Sot, eselyes is mert kozben ezt talaltam:
QEMU 7.2.9 monitor - type 'help' for more information
(qemu) info mtree
[...]
memory-region: system
[...]
0000000010000000-0000000010000007 (prio 0, i/o): serial
0000000010001000-00000000100011ff (prio 0, i/o): virtio-mmio
[...]
Ez ugye megerositi azt hogy:
[ 0.251717] 10000000.serial: ttyS0 at MMIO 0x10000000 (irq = 1, base_baud = 230400) is a 16550A
Meg azt is hogy a 8250-es 8 regisztere az byte-szinten (0 bitshift mellett) van elosztva.
Node a lenyeg az az hogy latszik hogyha tobb -serial-t adok meg neki, akkor is csak egy ilyen i/o: serial modult ir ki az `info mtree`, illetve a port=... argumentumot sem veszi be. Mondjuk ettol fuggetlenul ezek az `info ...` akarmik elegge szegenyesnek tunnek, pl az is furcsa hogy az `info irq` semmit nem ir ki (pedig ez a 8250/16550-es az azert tud megszakitasokat kezelni). Szoval siman lehet, tenyleg, hogy ebbe a `qemu-system-riscv32`-be bele van vasalva az 1 szem soros port, egy adott cimre, oszt ennyi.
- A hozzászóláshoz be kell jelentkezni
Egyébként pontosan mire van szükséged a guest-ben? Az érintett riscv32 "virt" board támogatja mind a virtio-mmio, mind a virtio-pci transzportot, tehát virtio-serial port-od / konzolod egy csomó lehet. Azt tudod használni a guest oldalról?
- A hozzászóláshoz be kell jelentkezni
Ez egy nagyon minimal Linux, egyelore "lentrol felfele" epitem fel (azaz elso korben csak egy /init, ami csak busybox, az is initramfs-bol, a kernelbol hardveresen minden hianyzik, csak soros port az egyetlen fizikai device amit tamogat, stb). A kulvilag fele egy szem soros konzol van csak, es ezt akarom novelni egy plusz csatornaval, amin keresztul valami mast huznek ki (pl internetet, slattach-csel).
Koszi, ezt a virtio-t megnezem! Legalabbis azt latom hogy a kernel az tamogatja (egy CONFIG_VIRTIO_CONSOLE-t talaltam). Es a host oldalarol azt is latom hogy van - vagyis azt latom hogy valami van:
0000000010000000-0000000010000007 (prio 0, i/o): serial
0000000010001000-00000000100011ff (prio 0, i/o): virtio-mmio
0000000010002000-00000000100021ff (prio 0, i/o): virtio-mmio
0000000010003000-00000000100031ff (prio 0, i/o): virtio-mmio
0000000010004000-00000000100041ff (prio 0, i/o): virtio-mmio
[...]
mindez kozvetlenul a 8250-es MMIO blokkja felett, kicsit furcsa leosztasban de van 8 ilyen blokk. Meg akkor az eleszteset megnezem... hatha :)
- A hozzászóláshoz be kell jelentkezni
Az "info mtree" kimenetében a virtio-mmio transzport blokkokat látod, ezekre lehet ráültetni virtio device-okat. Jelen esetben 1 db virtio-serial device-ra lenne szükség, 1 db nem-konzol virtio-serial port-tal.
A frontend konfiguráció úgy nézne ki, hogy
-device virtio-serial-device,id=vser0 \
-device virtserialport,bus=vser0.0,nr=1,chardev=ch0,name=foobar \
a backend konfig pedig (mondjuk)
-chardev serial,id=ch0,path=/dev/ttyS0 \
A guest-ben elvileg kell majd látnod egy "/dev/virtio-ports/foobar" symlink-et, ami a "../vport1p1"-re mutat (ami már egy char device).
Ez egyébként egy nagyon egyszerű device, tehát egy valódi soros terminálhoz képest kevés jellemzővel rendelkezik; legjobb esetben is csak cols*rows meta-információt (= karakteres konzol felbontását) tudja átvinni: https://docs.oasis-open.org/virtio/virtio/v1.1/cs01/virtio-v1.1-cs01.ht…
"Internet behúzására" jó lehet a virtio-net-device, illetve a virtio socket device.
- A hozzászóláshoz be kell jelentkezni
Koszi! Igy mar tenyleg jol elindul a QEMU, a kernelt is ujraforditottam:
linux-6.1.92$ cat .config | grep VIRTIO | grep "^CONFIG"
CONFIG_BLK_MQ_VIRTIO=y
CONFIG_VIRTIO_CONSOLE=y
CONFIG_VIRTIO_ANCHOR=y
CONFIG_VIRTIO=y
de sajna sem az `info mtree`-ben, sem a guest-ben nem latszik semmi valtozas. A kernelnek csak a "console=ttyS0 nr_uarts=4" command line van atpasszolva, ahol ezutobbi opcio nyilvan ertelmetlen azalapjan amit irtal ha a csak a VIRT_UART0 van definialva. Lehet hogy kell meg mas command line argument is? Itten a kutatkodas kozben valahogy atjott az hogy a DTS/DTB-t is le tudom kerni amit a QEMU atpasszol - de aztan most hirtelen nem talalom hogy hogy is volt... ha ott hianyzik az megmagyaraz(hat) dolgokat.
[...]
Megneztem, a DTS-ben csak ilyenek lesznek:
virtio_mmio@10001000 {
interrupts = <0x01>;
interrupt-parent = <0x03>;
reg = <0x00 0x10001000 0x00 0x1000>;
compatible = "virtio,mmio";
(es mindez 8x, a 0x10001000 ... 0x10008000 cimeken). Szoval semmi sem utal a DTB/DTS-ben arra hogy ez igy egy valami lenne :/
- A hozzászóláshoz be kell jelentkezni
A device tree-ben a virtio_mmio regiszter blokkoknál konkrétabbat nem fogsz látni; a konkrét virtio eszköztípusokat a kernel driver(ek)nek kell felderíteniük, a virtio protokoll szerint.
Az info mtree-ben viszont látszani kellene a változásnak!
Említetted azt is, hogy a guest userland teljesen le van csupaszítva. Így valószínűleg systemd/udev hiányában nem jönnek létre a vport1p1 és társai device node-ok, valamint a rájuk mutató /dev/virtio-ports/* symlink-ek.
... Hm, ennek a "drivers/char/Kconfig" ellentmond:
config VIRTIO_CONSOLE
tristate "Virtio console"
depends on TTY
select HVC_DRIVER
select VIRTIO
help
Virtio console for use with hypervisors.
Also serves as a general-purpose serial device for data
transfer between the guest and host. Character devices at
/dev/vportNpn will be created when corresponding ports are
found, where N is the device number and n is the port number
within that device. If specified by the host, a sysfs
attribute called 'name' will be populated with a name for
the port which can be used by udev scripts to create a
symlink to the device.
Ezek szerint a vport1p1-nek létre kellene jönnie... valóban, a kernel forrásban ("drivers/char/virtio_console.c") benne van a device node létrehozása.
Hm hm hm... A következő be van állítva a guest kernel-ed konfigjában?
config VIRTIO_MMIO
tristate "Platform bus driver for memory mapped virtio devices"
depends on HAS_IOMEM && HAS_DMA
select VIRTIO
help
This drivers provides support for memory mapped virtio
platform device driver.
If unsure, say N.
Ez szabályozza a virtio-mmio transport driver-t (drivers/virtio/virtio_mmio.c), és enélkül semmi nem fog ráugrani azokra a bizonyos virtio_mmio regiszter blokkokra a device tree-ben.
Szerk.: ja most látom a fenti grep-ed kimenetéből, hogy a VIRTIO_MMIO tényleg nincs beállítva; akkor azt javaslom.
- A hozzászóláshoz be kell jelentkezni
Szerk.: ja most látom a fenti grep-ed kimenetéből, hogy a VIRTIO_MMIO tényleg nincs beállítva; akkor azt javaslom.
Hm... ezt most nezem, de a 6.1.92-esben meg nincs benne egyatalan. Megneztem a masik mainline-t (6.6.32), abban mar benne van. Ugyhogy akkor forditok egy ilyet. Lehet hogy akkor az MMIO support az ujabb, es a VIRTIO az alapbol PCI-re van kihegyezve. A RISC-V meg ugye kozvetlenul MMIO alapu.
Szerk: igen, kozben a 6.6.32-es is megy, es ha megadom a "virtio_mmio.device=0x200@0x10001000:4:0" cmdline-t a kernelnek, akkor meg is jelenik a dmesg-ben az hogy:
[ 0.266855] virtio-mmio 10001000.virtio_mmio: can't request region for resource [mem 0x10001000-0x10001fff]
[ 0.267246] virtio-mmio: probe of 10001000.virtio_mmio failed with error -16
Szoval valoszinuleg ezen az "az info mtree-ben viszont látszani kellene a változásnak" dolgon bukik el a dolog, amit irsz. Mert ott ugye tovabbra sem jelenik (miert is kerulne bele, csak a guest kernel frissitesevel). Most egyebkent igy inditom az egeszet:
#Image=./Image-6.1.92
Image=./Image-6.6.32
/usr/bin/qemu-system-riscv32 -m 512M -nographic -machine virt \
-kernel ${Image} \
-initrd ./initramfs.cpio.gz \
-append "console=ttyS0 virtio_mmio.device=0x200@0x10001000:4:0" \
-device virtio-serial,id=vser0 \
-device virtserialport,bus=vser0.0,chardev=ch0,name=foobar \
-chardev serial,id=ch0,path=/dev/tnt2 \
-serial /dev/tnt0
Szoval igen, itt meg nyomozni kell :)
- A hozzászóláshoz be kell jelentkezni
guest-ben a "cat /proc/iomem" mit mond?
Felteszed a guest kernelt meg az initrd-t valahova, ahonnan le tudom tölteni? :)
- A hozzászóláshoz be kell jelentkezni
...megvan a probléma; én a korábbi kommentemben azt írtam, hogy "-device virtio-serial-device", a Te parancssorodban viszont az áll, hogy "-device virtio-serial". Mind a két opció értelmes, az utóbbi azonban a pcie.0 buszra teszi rá a virtio serial device-t, tehát PCIe transzportot fog használni, és nem MMIO-t.
Miután kijavítod a device model nevét "virtio-serial"-ról "virtio-serial-device"-ra, az "info qtree" monitor parancs kimenetében ezt fogod látni:
dev: virtio-mmio, id ""
[...]
mmio 0000000010008000/0000000000000200
bus: virtio-mmio-bus.7
type virtio-mmio-bus
dev: virtio-serial-device, id "vser0"
[...]
bus: vser0.0
type virtio-serial-bus
dev: virtserialport, id ""
[...]
- A hozzászóláshoz be kell jelentkezni
Aha, koszi, alakul! Igen, azt lattam en is hogy a 0x10008000-as cimre pakolta (miert, kerdem en), es igy modositva a command line-t mar a kernel is a 0x10008000-as cimen kezdi keresni - de egyelore sikertelenul:
[ 0.195194] virtio-mmio: Registering device virtio-mmio.0 at 0x10008000-0x100081ff, IRQ 16.
[...]
[ 0.255124] virtio-mmio 10008000.virtio_mmio: can't request region for resource [mem 0x10008000-0x10008fff]
[ 0.255601] virtio-mmio: probe of 10008000.virtio_mmio failed with error -16
A /proc/iomem meg most ezt mondja:
10000000-100000ff : serial
10008000-100081ff : virtio-mmio.0
10008000-100081ff : virtio-mmio.0 virtio-mmio.0
80000000-8001ffff : Reserved
80400000-9fffffff : System RAM
80401000-81cde51f : Kernel image
80401000-80822e4b : Kernel code
81400000-817fffff : Kernel rodata
81c00000-81c9d4d7 : Kernel data
81c9e000-81cde51f : Kernel bss
Ez ugy hellyel-kozzel ertelmesnek tunik, de lehet hogy a jo az nem ilyen :)
- A hozzászóláshoz be kell jelentkezni
A következő nálam működik:
qemu-system-riscv32 \
-nodefaults \
\
-machine virt \
-m 512M \
\
-kernel Image-6.6.32 \
-initrd ./initramfs.cpio.gz \
-append 'console=ttyS0' \
\
-device virtio-serial-device,id=vser0 \
-device virtserialport,bus=vser0.0,chardev=ch0 \
-chardev socket,id=ch0,server=on,wait=on,path=sock \
\
-serial chardev:ch1 \
-mon chardev=ch1 \
-chardev stdio,id=ch1,mux=on \
Ez azt csinálja, hogy a qemu stdin-jén/stdout-ján a monitor és a guest normál soros portja van multiplexelve, valamint létrehoz 1db virtio-serial port-ot a guest-ben, amely a host oldalon a "sock" nevű UNIX domain socket-tel van összekötve. A qemu létrehozza (bind-olja) ezt a socket-et, de addig nem kezdi futtatni a guest-et, amíg a socket-re rá nem csatlakozik egy másik (host) processz.
Nevezett másik host processz legyen ez (másik terminálból futtatandó):
socat STDIO UNIX-CONNECT:sock
Amikor pedig a guest-ben elérjük a root shell-t, akkor ott futtassuk az alábbit:
socat GOPEN:/dev/vport0p1 STDIO
Amit az egyik socat-nál begépelünk (+Enter), az a másikon megjelenik, tehát a virtio-serial port működik.
- A hozzászóláshoz be kell jelentkezni
Ah, teljesen jo... akkor csak a virtio-serial-device leirason kellett egy kicsit valtoztatni. Ha jol latom, pont a kernel command line kavarta meg a dolgot, tkp csak azt kellett kiszedni az enyembol es mar jo is lett. Es az a vicc hogyha a cmdline-ban a 0x10001000-s cimet adom meg, akkor _jo_, ha meg azt ahova tenylegesen be is teszi, a 0x10008000-asat, akkor meg rossz... szoval nyeh...
Koszi megegyszer :)
- A hozzászóláshoz be kell jelentkezni
a kutatkodas kozben valahogy atjott az hogy a DTS/DTB-t is le tudom kerni amit a QEMU atpasszol
Ehhez külön hozzáfűzném, hogy a QEMU által generált DTB-t a QEMU közvetlenül ki tudja írni file-ba, egyrészt a "-machine dumpdtb=FILENAME" parancssori opcióval (amikor is a QEMU aztán nem is indul el rendesen), másrészt normál futás közben a "dumpdtb FILENAME" monitor paranccsal.
- A hozzászóláshoz be kell jelentkezni
Igenigen, koszi, ezek azok, kozben meglett :]
- A hozzászóláshoz be kell jelentkezni