Integrated debugger inside kernel

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
vvaltchev
Member
Member
Posts: 274
Joined: Fri May 11, 2018 6:51 am

Re: Integrated debugger inside kernel

Post by vvaltchev »

Korona wrote:@vvaltchev: Do you have physical hardware where 0x3F8 does not work? On the machines that I tested on (even newer ones), COM1 is still at that port (but COM 2, 3, 4 might not be at their legacy addresses - I have not checked that).
Actually yes, I have an UDOO x86 with two UART controllers, none of them accessible thought the legacy interface. On Linux I also see hidden serial ports on my Lenovo laptop, still not accessible from 0x3f8. That, combined with the fact that hardware today is generally exposed thought enumerable interfaces and that serial ports are not built-in anymore in PCs, but require a PCI card or an USB adapter, made me assume that on almost all the machines in the last 10-15 years, the classic interface won’t work.

But, my perspective is biased by my own experience and can be incorrect in the general case, I don’t know.
Tilck, a Tiny Linux-Compatible Kernel: https://github.com/vvaltchev/tilck
vvaltchev
Member
Member
Posts: 274
Joined: Fri May 11, 2018 6:51 am

Re: Integrated debugger inside kernel

Post by vvaltchev »

Octocontrabass wrote:Well, there you go. Your serial port is using I/O port 0x3F8 and (ISA) IRQ 4.

If the serial port doesn't echo back the data you send when you short pins 2 and 3 together (with nothing else connected), the UART isn't programmed correctly.
Yeah, I’m totally surprised, but Bonfra’s serial port is really available using the classic interface.
Now it’s clear that the problem is either in the way the UART is programmed in his kernel, or in the way the receiver is configured.

@Bonfra, you could check if the receiver is configured correctly by using another OS instead of yours and making sure the communication works both ways. If that’s all OK, the problem is exclusively in your kernel. Let me just throw a theory: maybe you don’t wait the mandatory 2 microseconds in the right places? Such things don’t really matter in VMs, but on real hw, they do.
Tilck, a Tiny Linux-Compatible Kernel: https://github.com/vvaltchev/tilck
User avatar
pvc
Member
Member
Posts: 201
Joined: Mon Jan 15, 2018 2:27 pm

Re: Integrated debugger inside kernel

Post by pvc »

Bonfra wrote:Do I need to connect together those two pins on their own or does the cable need to be plugged to the other end? it's a bit trivial to shorten them while it's connected. I tried to connect just these two pins without plugging the cable and nothing is sent back, maybe I need to do something else with the other pins?
Short the pins without connecting the other end. I often used metal tweezers to do that :wink:. But it would be safer, for the hardware, to use some kind of resistor (maybe about 100 ohms). For simple 8N1 transmission, only these 2 pins need to be shorted. You would need others if you used hardware flow control. Also, it is possible that the port itself is toast or flaky.
User avatar
Bonfra
Member
Member
Posts: 270
Joined: Wed Feb 19, 2020 1:08 pm
Libera.chat IRC: Bonfra
Location: Italy

Re: Integrated debugger inside kernel

Post by Bonfra »

vvaltchev wrote: Let me just throw a theory: maybe you don’t wait the mandatory 2 microseconds in the right places? Such things don’t really matter in VMs, but on real hw, they do.
I use a pause instruction to waste some time, maybe I should read to some blank port instead? This is all the code I use for uart I/O:

Code: Select all

uart_init:
    push rax
    push rdx

    mov dx, 0x3f9
    ; IER int off
    xor al, al
    out dx, al
    ; LCR set divisor mode
    mov al, 0x80
    add dl, 2
    out dx, al
    ; DLL divisor lo 115200
    mov al, 1
    sub dl, 3
    out dx, al
    ; DLH divisor hi
    xor al, al
    inc dl
    out dx, al
    ; FCR fifo off
    inc dl
    out dx, al
    ; LCR 8N1, break on
    mov al, 0x43
    inc dl
    out dx, al
    ; MCR Aux out 2
    mov al, 0x8
    inc dl
    out dx, al
    ; clear receiver/transmitter
    xor al, al
    sub dl, 4
    in al, dx

    pop rax
    pop rdx
    ret

; Param RDI[low8] => character to put
uart_putc:
    push rax
    push rcx
    push rdx
    mov ecx, 10000
    mov dx, 0x3fd
.one:
    in al, dx
    pause
    cmp al, 0xff
    je .two
    dec ecx
    jz .two
    and al, 0x20
    jz .one

    mov ax, di
    sub dl, 5
    out dx, al
.two:

    pop rdx
    pop rcx
    pop rax
    ret

uart_getc:
    push rdx

    xor rax, rax

    mov dx, 0x3fd
.one:
    pause
    in al, dx
    and al, 1
    jz .one
    sub dl, 5
    in al, dx

    cmp al, 13 ; '\r'
    jne .done
    mov al, 10 ; '\n'
.done:

    pop rdx
    ret
very "inspired" from bzt's.
vvaltchev wrote: you could check if the receiver is configured correctly by using another OS instead of yours and making sure the communication works both ways. If that’s all OK, the problem is exclusively in your kernel.
Tomorrow I'll burn a small Linux distro to test this, anyway I'm going to set the baud rate of the port with `stty` and then just `cat` the port to read and `echo` to write. Is this enough?
Regards, Bonfra.
User avatar
Bonfra
Member
Member
Posts: 270
Joined: Wed Feb 19, 2020 1:08 pm
Libera.chat IRC: Bonfra
Location: Italy

Re: Integrated debugger inside kernel

Post by Bonfra »

pvc wrote: Short the pins without connecting the other end. I often used metal tweezers to do that :wink:. But it would be safer, for the hardware, to use some kind of resistor (maybe about 100 ohms).
Uhm I used an Arduino cable, hope I didn't fry anything XD
Regards, Bonfra.
rdos
Member
Member
Posts: 3297
Joined: Wed Oct 01, 2008 1:55 pm

Re: Integrated debugger inside kernel

Post by rdos »

I don't use ACPI to discover legacy COM-ports, simply because ACPI on older machines often is not available or not usable. It's easy enough to probe serial ports since they can generate interrupts that can be detected. Some BIOS doesn't configure the hardware correctly, so today I reprogram them completely. Legacy COM-ports have a limited number of IO-addresses (I check 3F8, 2F8, 3E8, 2E8, 2A0, and 2A8). For PCI-based COM ports, I check for specific PCI vendor & product combinations. I support two IO-based and one memory-based PCI COM adaptor. There are many PCI addons that require custom drivers, and you probably don't want to support these unless you need to.

The next issue is that practically no modern computer has serial ports, and so debugging using serial ports doesn't seem like a good idea. Sure, there are USB to serial converters, but using those requires a functions USB stack and a functional USB COM driver, and many problems with real hardware are connected to USB. You also need functional OHCI, UHCI, EHCI, XHCI and USB hub implementations to make use of it.

I think a far better method to debug an OS is to use the network interface. At least on many PCs there are real Ethernet connectors and many computers use the same network chipsets (often RTL8169 or compatible). However, this is changing too and today laptops typically don't have an Ethernet connector either, again needing functional USB drivers or Wifi driver (which often have no documentation).

As for kernel debugging, I don't think this should be done remotely at all, rather should be a device-driver integrated with the scheduler and a "sand-box" (panics).
User avatar
Bonfra
Member
Member
Posts: 270
Joined: Wed Feb 19, 2020 1:08 pm
Libera.chat IRC: Bonfra
Location: Italy

Re: Integrated debugger inside kernel

Post by Bonfra »

rdos wrote: The next issue is that practically no modern computer has serial ports, and so debugging using serial ports doesn't seem like a good idea. Sure, there are USB to serial converters, but using those requires a functions USB stack and a functional USB COM driver, and many problems with real hardware are connected to USB. You also need functional OHCI, UHCI, EHCI, XHCI and USB hub implementations to make use of it.
The computer with my os has the serial port, the other pc where I should receive data does not have it so I use a USB adapter, literally this cable. could this be the issue?
rdos wrote: I think a far better method to debug an OS is to use the network interface. At least on many PCs there are real Ethernet connectors and many computers use the same network chipsets (often RTL8169 or compatible).
Can you tell me more about this? Or link some resources I can read?
Regards, Bonfra.
User avatar
pvc
Member
Member
Posts: 201
Joined: Mon Jan 15, 2018 2:27 pm

Re: Integrated debugger inside kernel

Post by pvc »

rdos wrote:The next issue is that practically no modern computer has serial ports, and so debugging using serial ports doesn't seem like a good idea.
I would like to disagree. Many modern, 'non-budget' motherboards still have physical serial ports. On server boards serial port is a norm. There are also many PCI/PCIe adapters. Most of these are usually compatible with good old 16550. So I think using serial port for debugging is perfectly good idea. Easy to program and require very little of the OS still functioning, even when most of the OS went kaput.

I use GDB over serial port for real machine debugging and it works just fine on my main, X570 machine (both ways, as debugger and as debugee).
vvaltchev
Member
Member
Posts: 274
Joined: Fri May 11, 2018 6:51 am

Re: Integrated debugger inside kernel

Post by vvaltchev »

Bonfra wrote:I use a pause instruction to waste some time, maybe I should read to some blank port instead?
I believe "pause" is a sort of NOP designed to be used while spinning. I believe you would need (in general) a proper udelay(microseconds) function. But, I'm not sure at all that's your problem here. After checking some code, it looks to me that you might need udelay() only during the initialization. That's different from the PS/2 controller case I was thinking about where delays are used in many more cases.

Note: I haven't checked your assembly code as I always used a C implementation, using: https://wiki.osdev.org/Serial_Ports as a starting point.
Bonfra wrote:Tomorrow I'll burn a small Linux distro to test this, anyway I'm going to set the baud rate of the port with `stty` and then just `cat` the port to read and `echo` to write. Is this enough?
I'd would check using minicom at both sides.
Tilck, a Tiny Linux-Compatible Kernel: https://github.com/vvaltchev/tilck
vvaltchev
Member
Member
Posts: 274
Joined: Fri May 11, 2018 6:51 am

Re: Integrated debugger inside kernel

Post by vvaltchev »

Bonfra wrote:The computer with my os has the serial port, the other pc where I should receive data does not have it so I use a USB adapter, literally this cable. could this be the issue?
I don't think that could be the problem. Actually, your cable-adapter seems good to me, as it supports hardware control flow signals like RTS and DTR. I tested a serial-to-usb adapter worse (without HW control flow) than this between two Linux machines and worked great with minicom. Probably, there's a problem somewhere with your code.

Ah, oops, there's ONE MORE THING: on modern Linux kernels (from 4.11), it's not possible anymore from user space to directly write to serial ports (not talking to the usb-adapter side). See: https://youtu.be/wIQPb1NkZbQ

So, to make the test between the "primary" machine with the USB and the "secondary" machine with the COM port, I believe you'd need, on the secondary machine, to either re-build the Linux kernel without serdev or to use an older Linux kernel or somehow to enable serdev-ttydev (not sure how to do that).
Tilck, a Tiny Linux-Compatible Kernel: https://github.com/vvaltchev/tilck
rdos
Member
Member
Posts: 3297
Joined: Wed Oct 01, 2008 1:55 pm

Re: Integrated debugger inside kernel

Post by rdos »

pvc wrote:
rdos wrote:The next issue is that practically no modern computer has serial ports, and so debugging using serial ports doesn't seem like a good idea.
I would like to disagree. Many modern, 'non-budget' motherboards still have physical serial ports. On server boards serial port is a norm. There are also many PCI/PCIe adapters. Most of these are usually compatible with good old 16550. So I think using serial port for debugging is perfectly good idea. Easy to program and require very little of the OS still functioning, even when most of the OS went kaput.

I use GDB over serial port for real machine debugging and it works just fine on my main, X570 machine (both ways, as debugger and as debugee).
Maybe if we talk about stationary computers, particularly if you can build them yourself then you can always find a motherboard with a real serial port (and a PS/2 port). However, if you prefer portable computers, then basically none have real serial ports.

I also disagree that a serial port can be used with GDB when the kernel goes kaput. In those cases, the IRQs might not work, and you might not have a scheduler that is running, and so the stub in your OS is likely to be out of order too.

I have an option to link a serial port to the panic monitor and that way simulate a keyboard, but that's the only case when I use this. In this case, I actually poll the serial port since I cannot rely on IRQs working in the panic monitor. OTOH, it would be possible to add support for attaching the Watcom debugger through a serial port to get symbolic information for the currently running code and even trace it. However, this is post-mortem debugging and cannot be used for more normal debugging as the kernel is no longer running.

I could build a trap for debugging over a serial port using Watcom's wdw debugger, but that will slow down things considerably compared to using the network. I don't support attaching the debugger to the kernel, but an application could step into kernel space and debug C-based device drivers that way. However, my application debugger doesn't freeze the complete application when debugging, rather only stops debugged threads. That's also why it can step into the kernel without freezing the kernel.
User avatar
Bonfra
Member
Member
Posts: 270
Joined: Wed Feb 19, 2020 1:08 pm
Libera.chat IRC: Bonfra
Location: Italy

Re: Integrated debugger inside kernel

Post by Bonfra »

vvaltchev wrote:I always used a C implementation, using: https://wiki.osdev.org/Serial_Ports as a starting point.
I tried the wiki's code for initialization and it returns error; that thing where it tries to write to the port and read back fails.
So I tried to boot a small Linux distro in that computer to test the serial port but it does not show up
Image
vvaltchev wrote:Ah, oops, there's ONE MORE THING: on modern Linux kernels (from 4.11), it's not possible anymore from user space to directly write to serial ports (not talking to the usb-adapter side)
I think this is the reason.
But knowing the initialization piece of code from the wiki fails is something to work right?
Regards, Bonfra.
vvaltchev
Member
Member
Posts: 274
Joined: Fri May 11, 2018 6:51 am

Re: Integrated debugger inside kernel

Post by vvaltchev »

Bonfra wrote:But knowing the initialization piece of code from the wiki fails is something to work right?
Well, yeah.. but until you test that everything works using a well-known reliable implementation on both sides, there's always the risk that you might be focusing on the wrong problem. Just pick up an old Linux and try a two-way communication using minicom.
Tilck, a Tiny Linux-Compatible Kernel: https://github.com/vvaltchev/tilck
nexos
Member
Member
Posts: 1081
Joined: Tue Feb 18, 2020 3:29 pm
Libera.chat IRC: nexos

Re: Integrated debugger inside kernel

Post by nexos »

vvaltchev wrote:Ah, oops, there's ONE MORE THING: on modern Linux kernels (from 4.11), it's not possible anymore from user space to directly write to serial ports
Why in the world did they do that? Some people still use serial ports! Anyway, @Bonfra, try testing the serial code in QEMU and see if anything gets sent to the serial monitor.
"How did you do this?"
"It's very simple — you read the protocol and write the code." - Bill Joy
Projects: NexNix | libnex | nnpkg
vvaltchev
Member
Member
Posts: 274
Joined: Fri May 11, 2018 6:51 am

Re: Integrated debugger inside kernel

Post by vvaltchev »

nexos wrote:Why in the world did they do that? Some people still use serial ports!
Watch this for the whole story: https://youtu.be/wIQPb1NkZbQ
Briefly, there are uses cases of multiple applications using the serial port, so multiplexing must be done in user space but, at any moment, an "evil" program can always mess up everything by writing directly to the serial port (e.g. /dev/ttyS0). They wanted to clean that up, by treating the serial ports as buses, like USB. Now, you need custom driver to communicate with each kind of serial device at the other side. But, in theory, there is still a way to use the serial ports as TTY, just it's not as straightforward as it was before.
nexos wrote:Anyway, @Bonfra, try testing the serial code in QEMU and see if anything gets sent to the serial monitor.
In my understanding, his code already works on QEMU. The problem is only with real hardware.
Tilck, a Tiny Linux-Compatible Kernel: https://github.com/vvaltchev/tilck
Post Reply