ghaerr / elks

Embeddable Linux Kernel Subset - Linux for 8086
Other
984 stars 106 forks source link

[integration] Adding a random NE2K card on a 80c188 #1017

Closed cocus closed 2 years ago

cocus commented 2 years ago

Hi all! After some really exciting development, we have some really cool support for embedded 8018x CPUs. My board wasn't conceived as a SBC, nor as something you could use beyond the intended usage the manufacturer gave to it. Of course that doesn't stop me to use it as I would like to. I have the entire address/IO mapped out, and I took out all the ICs that weren't useful for my usage. Now it's the time to add a network card, and for such task I have 3 different ISA cards that I could use. Note that this device doesn't even have an ISA connector, so I would have to hack up a connector, or route all the necessary pins from it to the network card. Since it's an 8 bit bus, I can't use any of the cards in NE2K mode, but rather NE1K. I can use one of the following cards:

All of them have a coax+twisted pair connectors, and an I2C EEPROM. This might contain the configuration stored by a DOS software whenever they were last used, and I think I need to boot a DOS machine with the appropriate software for them to reset their config or at least know what's configured.

I'm a complete noob to the ISA bus, but I understand that the address and data bus is routed there, alongside some control signals like R/W, etc. IRQs are also there, but my board doesn't have an IRQ controller, but the CPU does handle that. So if I know that the card wants to use IRQ3, I could connect the appropriate IRQ3 pin into one of the 4 external IRQ pins on my CPU and deal with the IRQ mappings in software (well, there's NO support for external IRQs yet, so this would be the first thing using it). I also know that an 8MHz clock needs to be feeded there. I don't have that, but I think I could either derive it from the CPU clock with two flip flops (it's a 32MHz crystal, but the F_CPU is 1/2 of it) or understand if there's some kind of timer that I could use on the CPU to generate 8MHz constantly. Besides that, I should provide 5V and probably 12V. I will double check if the pins for these things are used.

I would like to understand if any of the above cards have some advantages over another card, so I could pick one to begin working on this.

After picking one up, I need to understand how to enable its appropriate driver on ELKS and which parts of it need to be modified.

All help and tips would be greatly appreciated.

Thanks!

EDIT: I checked that none of these cards use the -12V or 12V rails, DMA related lines, nor the 8MHz clock; just the some address lanes, low-order data and some IRQ lines. On the 16bit expansion, I saw they use the SDxx lanes, some IRQs and the /IOCS16. They don't use /MEMCS16, /MEMWR /MEMR. I need to figure out how the /IOCS16 lane works, and if I could disregard it completely or not. Besides that, it think the interface should be straightforward to the 80c188.

ghaerr commented 2 years ago

Hello @cocus,

I'm not the one to ask about NIC hardware, but still have some comments. It sounds like you'll have your work cut out for you wiring together an ISA interface to your board, and you may need to test basic communications with it using a new or modified kernel driver, while you get it up and running, as well as the interrupt handling for it and the kernel as well.

ELKS really only has two NIC device drivers: a NE2K in ne2k.c with lots of ASM code in ne2k-asm.S. It handles NE2K compatibility out of the box, and should be very easily modified for 8-bit access (is that NE1K?).

The other driver, wd.c, is for WD8003 NICs and variants. It's considerably smaller and is written entirely in C, so it is much more understandable and maintainable, IMO. However, where you start probably depends on how close your chip is to either of the existing drivers.

Both drivers handle interrupts a bit differently than you might think - they register an interrupt routine with request_irq, but the interrupt routine doesn't actually do any I/O; instead it reads a status register that saves information for both TX and RX readiness, and then wakes up the associated user program(s) that may be waiting on a packet read or write. The actual packet read or write is then done by that kernel task. This saves lots of potential issues and keeps almost all operations done in "normal" kernel time.

Once you pick the software driver you'd like to start with, it's probably easiest to just modify it until you get it working, then we can determine whether to make a subdriver out of your work, or just add the modified files as a new driver.

Thank you and keep us posted on your progress!

Mellvik commented 2 years ago

Hi @cocus, Like @ghaerr pointed out - you'll have your work cut out for you.

Since you don't have a working ISA bus, I would suggest starting with something simpler than an ethernet interface to get the ISA bus running. Like a serial og parallell interface. Maybe serial - since that's something you know a lot about already. Then, when you have a working ISA bus, start the work in Ethernet.

Again as pointed out by @ghaerr, you have a great starting point with the current ethernet drivers. They have a lot in common because the Ethernet chip is the same (or similar). The NE2k (16bit) and NE1k (8bit) use programmed IO (or DMA, which is currently not used in ELKS). The WD8003 (8bit) uses shared memory. BTW - don't get confused by the use of the term DMA in the NE2k driver: The DMA in question is ON the network card ('direct memory access to the on board memory'), not between the card and the system.

We're looking forward to following your progress!

—Mellvik

  1. nov. 2021 kl. 02:23 skrev Gregory Haerr @.***>:

Hello @cocus https://github.com/cocus,

I'm not the one to ask about NIC hardware, but still have some comments. It sounds like you'll have your work cut out for you wiring together an ISA interface to your board, and you may need to test basic communications with it using a new or modified kernel driver, while you get it up and running, as well as the interrupt handling for it and the kernel as well.

ELKS really only has two NIC device drivers: a NE2K in ne2k.c with lots of ASM code in ne2k-asm.S. It handles NE2K compatibility out of the box, and should be very easily modified for 8-bit access (is that NE1K?).

The other driver, wd.c, is for WD8003 NICs and variants. It's considerably smaller and is written entirely in C, so it is much more understandable and maintainable, IMO. However, where you start probably depends on how close your chip is to either of the existing drivers.

Both drivers handle interrupts a bit differently than you might think - they register an interrupt routine with request_irq, but the interrupt routine doesn't actually do any I/O; instead it reads a status register that saves information for both TX and RX readiness, and then wakes up the associated user program(s) that may be waiting on a packet read or write. The actual packet read or write is then done by that kernel task. This saves lots of potential issues and keeps almost all operations done in "normal" kernel time.

Once you pick the software driver you'd like to start with, it's probably easiest to just modify it until you get it working, then we can determine whether to make a subdriver out of your work, or just add the modified files as a new driver.

Thank you and keep us posted on your progress!

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/jbruchon/elks/issues/1017#issuecomment-974989332, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA3WGOD4RTJQ6Y3NRAPXF2TUNGLP5ANCNFSM5IOQGRPA. Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

cocus commented 2 years ago

Hi @ghaerr and @Mellvik,

ELKS really only has two NIC device drivers: a NE2K in ne2k.c with lots of ASM code in ne2k-asm.S. It handles NE2K compatibility out of the box, and should be very easily modified for 8-bit access (is that NE1K?).

The other driver, wd.c, is for WD8003 NICs and variants. It's considerably smaller and is written entirely in C, so it is much more understandable and maintainable, IMO. However, where you start probably depends on how close your chip is to either of the existing drivers.

I think the three cards are NE2K compatible, but I wouldn't venture in using none other than the RTL8019 because I can't find any documentation on the other chipsets (UM8009F and DL2518); except maybe some DOS config tools or drivers. For the 8019, I have its datasheet and, at least, one circuit schematic that interfaces it to an 8 bit microcontroller using an 8 bit data bus. I only need to remove its config EEPROM and short two pins by the looks of it. MAYBE the other cards would work EXACTLY like the 8019 (they should, as they're NE2K compatible) but... I don't have high hopes.

Once you pick the software driver you'd like to start with, it's probably easiest to just modify it until you get it working, then we can determine whether to make a subdriver out of your work, or just add the modified files as a new driver.

Yeah, I assume I could use the default driver and apply the NCommander patches to get it working in 8 bit mode (not sure if still needed?).

Since you don't have a working ISA bus, I would suggest starting with something simpler than an ethernet interface to get the ISA bus running. Like a serial og parallell interface. Maybe serial - since that's something you know a lot about already. Then, when you have a working ISA bus, start the work in Ethernet.

Sadly I don't have any other ISA cards, except a sound card and a video card. I have the pinout used on that AVR microcontroller as a reference, from this PDF https://web.archive.org/web/20070129102917/https://www.ulrichradig.de/site/atmel/avr_webserver/pdf/AVRSmallWebServer.pdf. As stated, almost ALL pins are NC or going directly to GND or VCC. On this table, almost the entire address bus is hardcoded to be on the 0x300 region (only A0-A4 are addresseable). I'm thinking of continuing with this so I don't have to route 20 cables to my board. I think I can fool the 8019 by crafting the /IOW and /IOR lines with some glue logic and a spare GCSx from the 80C188 (which I can control and set it to be on the 0x300 IO range programatically); I think a simple NAND from the GCSx line and /WR (or /RD) should do the trick. Do you think it's worth doing this? Or should I route the 20 address bus pins?

Thanks!

ghaerr commented 2 years ago

Hello @cocus,

Perhaps using the RTL8019 NE2K-compatible card and the ne2k.c driver will be the way to go, and you won't run into too many problems wiring your board. I wired an S-100 bus together onto an incompatible system years ago, and it was actually kind of fun.

After you get that done, you can poke at it with a modified software driver to ascertain that you're talking to what looks like the register file and address space. As far as whether to wire up all 20 address lines, or add a bit of logic, if you've got a place to put that logic, that might save wiring 20 lines... not sure. You'll need to ensure the additional logic doesn't add further address decoding delay.

I could use the default driver and apply the NCommander patches to get it working in 8 bit mode (not sure if still needed?).

Yes, NCommander's patch will still be required, we never did add a config option nor even an option in the driver source to do that; I would like to have that done.

cocus commented 2 years ago

Well, sorry for the delay guys! I ended up doing some interesting hacks in order to get this working, and I think it does somewhat works. Sadly, I couldn't use the RTL8019, but I ended up using the DL2518 card. I previously configured it with the DOS tool on a random Pentium 2 I have, so it uses IRQ3, IO base 0x300 and its mac is set to 00400533ee34. On my board, I ended up remapping the IRQ3 of the ISA bus into INT1 on the CPU. Appropriate changes into the irq-8018x.c were added so NE2K_IRQ can be used transparently. I applied NCommander's patches to the ne2k-asm file so it uses 8 bit I/O. I also enabled the ne2k network driver in the menuconfig, nothing else.

Please review the following console log:

8018x ELKS loader built at Fri 17 Dec 2021 02:26:29 AM -03
Now jumping into ELKS...
console_init: 8018X UART
eth: NE2K at 0x300, irq 12, MAC 00:40:05:33:ee:34
ssd: 1977614336K disk
8018X machine, 512K base RAM.
ELKS kernel 0.4.0 (40720 text, 0 ftext, 4976 data, 33952 bss, 1232 heap)
Kernel text at e062:0000, data 80:0000, top 8000:0, 470K free
VFS: Mounted root 0x0600 (romfs filesystem).
No init - running /bin/sh
#

So, at this stage, I copied ktcp to my fat32-formatted SD card, and I tried to run it directly:

# ./ktcp -b 10.0.2.15 10.0.2.2 255.255.255.0
ktcp: can't open tcpdev device /dev/tcpdev

But /dev/tcp exists:

# ls /dev/tc*
/dev/tcpdev

I don't understand this error. Does it mens the driver can't communicate with the card? did I miss something that's preventing the card to work? The ne2k driver's fops shouldn't fail on open, only if it's in use, but shouldn't be the case.

Thanks!

Mellvik commented 2 years ago

Hi Santiago, congratulations - you have a working card and a (somewhat) working interface.

The clue is the MAC address: The driver is reading the address off of the card correctly, which means that a lot is working.

It doesn't mean interrupts are working though, that's the next step. After the tcpdev problem has been fixed. I'm sure @ghaerr will have a great clue about that one. I would start with checking that the file /dev/tcpdev actually exists, is a device and looks the same as it does in QEMU.

--Mellvik

  1. des. 2021 kl. 06:41 skrev Santiago Hormazabal @.***>:

 Well, sorry for the delay guys! I ended up doing some interesting hacks in order to get this working, and I think it does somewhat works. Sadly, I couldn't use the RTL8019, but I ended up using the DL2518 card. I previously configured it with the DOS tool on a random Pentium 2 I have, so it uses IRQ3, IO base 0x300 and its mac is set to 00400533ee34. On my board, I ended up remapping the IRQ3 of the ISA bus into INT1 on the CPU. Appropriate changes into the irq-8018x.c were added to allow the NE2K_IRQ to be used transparently. I also enabled the ne2k network driver in the menuconfig, nothing else.

Please review the following console log:

8018x ELKS loader built at Fri 17 Dec 2021 02:26:29 AM -03 Now jumping into ELKS... console_init: 8018X UART eth: NE2K at 0x300, irq 12, MAC 00:40:05:33:ee:34 ssd: 1977614336K disk 8018X machine, 512K base RAM. ELKS kernel 0.4.0 (40720 text, 0 ftext, 4976 data, 33952 bss, 1232 heap) Kernel text at e062:0000, data 80:0000, top 8000:0, 470K free VFS: Mounted root 0x0600 (romfs filesystem). No init - running /bin/sh # So, at this stage, I copied ktcp to my SD card, and I tried to run it directly:

./ktcp -b 10.0.2.15 10.0.2.2 255.255.255.0

ktcp: can't open tcpdev device /dev/tcpdev I don't understand this error. Does it mens the card is not working? did I miss something that's preventing the card to work?

Thanks!

— Reply to this email directly, view it on GitHub, or unsubscribe. Triage notifications on the go with GitHub Mobile for iOS or Android. You are receiving this because you were mentioned.

ghaerr commented 2 years ago

Hello Santiago,

Make sure CONFIG_INET and CONFIG_SOCKETS are turned on in .config. If CONFIG_INET is off, the open will fail.

/etc/tcpdev is the character device used by ktcp for communication with the kernel for all application network requests. This will be the first time networking is implemented on ROMFS, so there could be small issues. The driver itself lives in elks/arch/i86/drivers/char/tcpdev.c and debugging can be turned on, which will show the open request by setting DEBUG_NET in linuxmt/debug.h. I suppose ktcp should print the errno return, which might show more.

Thank you!

cocus commented 2 years ago

The clue is the MAC address: The driver is reading the address off of the card correctly, which means that a lot is working. It doesn't mean interrupts are working though, that's the next step. After the tcpdev problem has been fixed. I'm sure @ghaerr will have a great clue about that one. I would start with checking that the file /dev/tcpdev actually exists, is a device and looks the same as it does in QEMU.

Yeah, I might have an issue with my IRQ line. So here's a question that maybe you guys might know. I'm inverting the ISA-bus IRQ line so it goes negated to the CPU. By the looks of it, the ISA-bus makes an IRQ by a low-to-high transition on that line. My CPU also gets triggered by a low-to-high transition on the INT line, so I think this inverter is not right? However, when I probed the IRQ3 line with a voltmeter, I saw it "floating". This is not good. I don't see any pull downs on the original intel 8259 PIC, but should I add the? Does this mean that two ISA cards on the same bus that want to share the same IRQ are going to drive this line HIGH? which means that the card doesn't have the mean to source any current to these IRQ pins, but rather sink? (i.e. the inverse of an open drain)?

Make sure CONFIG_INET and CONFIG_SOCKETS are turned on in .config. If CONFIG_INET is off, the open will fail.

/etc/tcpdev is the character device used by ktcp for communication with the kernel for all application network requests. This will be the first time networking is implemented on ROMFS, so there could be small issues. The driver itself lives in elks/arch/i86/drivers/char/tcpdev.c and debugging can be turned on, which will show the open request by setting DEBUG_NET in linuxmt/debug.h. I suppose ktcp should print the errno return, which might show more.

I'll have to check this for sure!

Thanks!

ghaerr commented 2 years ago

My CPU also gets triggered by a low-to-high transition on the INT line, so I think this inverter is not right? However, when I probed the IRQ3 line with a voltmeter, I saw it "floating".

"floating", you mean high? I'm not a hardware guy, but I would think you'd need a resister to Vcc or Gnd to stabilize the value, depending on what it's connected to might do to it. Also, of course, the 8018X can be programmed for edge- or level-driven interrupts, correct? So what happens depends on the CPU interrupt programming.

On another note, it couldn't hurt to write a skeleton "driver" that printk's when an interrupt is received, so that you can test this out perhaps even with a pushbutton, before debugging the network driver! This would also allow you to test the edge/level triggering.

Mellvik commented 2 years ago

Santiago, I admire your determination diving into this rather bold project. My hardware skills are admittedly rusty, but I can tell you what I would do in your situation.

First of all, pull out some complete PC schematics from the Internet, there are plenty of them, as I found out last year when diagnosing a faulty floppy controller. I doubt you would need pullups or pulldowns on the 8259, but the schematics will tell you.

You should not have floating IRQ lines, they will create noise and trigger spurious interrupts. I would look closely to verify that both ends the actual are actually connected. Unless you have tri-(3-)state logic, which means that a gate can bee off, on, or ‘disconnected’. In that case, a floating line is fine, but does require that all ends are prepared for it (possibly pullup/pulldown). That said, a voltmeter is a really bad tool for this type of work. Get a logic probe with a reasonable bandwidth, it will probably cost you less than $20. And finally - IRQs may be shared, but not ‘galvanically’ (again unless you’re using tai-state logic), they must be shared via some logic, typically a OR gate.

Like @ghaerr said, put some printk's into the driver to see what’s going on with the interrupts. You can start with the #if 0 in the ne2k_int routine in ne2k.c, change it to #if 1 instead. Also, enable ethernet debug output by setting DEBUG_ETH to 1 on the debug.h file. Then you’ll immediately know when interrupts happen and what they are.

—Mellvik

Yeah, I might have an issue with my IRQ line. So here's a question that maybe you guys might know. I'm inverting the ISA-bus IRQ line so it goes negated to the CPU. By the looks of it, the ISA-bus makes an IRQ by a low-to-high transition on that line. My CPU also gets triggered by a low-to-high transition on the INT line, so I think this inverter is not right? However, when I probed the IRQ3 line with a voltmeter, I saw it "floating". This is not good. I don't see any pull downs on the original intel 8259 PIC, but should I add the? Does this mean that two ISA cards on the same bus that want to share the same IRQ are going to drive this line HIGH? which means that the card doesn't have the mean to source any current to these IRQ pins, but rather sink? (i.e. the inverse of an open drain)?

Make sure CONFIG_INET and CONFIG_SOCKETS are turned on in .config. If CONFIG_INET is off, the open will fail.

/etc/tcpdev is the character device used by ktcp for communication with the kernel for all application network requests. This will be the first time networking is implemented on ROMFS, so there could be small issues. The driver itself lives in elks/arch/i86/drivers/char/tcpdev.c and debugging can be turned on, which will show the open request by setting DEBUG_NET in linuxmt/debug.h. I suppose ktcp should print the errno return, which might show more.

I'll have to check this for sure!

Thanks!

— Reply to this email directly, view it on GitHub https://github.com/jbruchon/elks/issues/1017#issuecomment-997070759, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA3WGOEMA6UOBUU2KCVZXZTURO3L7ANCNFSM5IOQGRPA. Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub. You are receiving this because you were mentioned.

cocus commented 2 years ago

Well guys, you know me! I can't stop until I finish what I want.

"floating", you mean high? I'm not a hardware guy, but I would think you'd need a resister to Vcc or Gnd to stabilize the value, depending on what it's connected to might do to it. Also, of course, the 8018X can be programmed for edge- or level-driven interrupts, correct? So what happens depends on the CPU interrupt programming.

No, I measured the voltage on the IRQ3 line and I could change it by touching it with my finger. This means there's nothing driving it.

On another note, it couldn't hurt to write a skeleton "driver" that printk's when an interrupt is received, so that you can test this out perhaps even with a pushbutton, before debugging the network driver! This would also allow you to test the edge/level triggering.

I ended up changing the #if 0 to #if 1 on the irq handler for the ne2k driver. I didn't get anything first, but after I removed the NOT gate and a 1k pull up to this line, it worked! I had to enable the CONFIG_INET and CONFIG_SOCKETS configs since they weren't set on my kernel.

I admire your determination diving into this rather bold project. My hardware skills are admittedly rusty, but I can tell you what I would do in your situation. First of all, pull out some complete PC schematics from the Internet, there are plenty of them, as I found out last year when diagnosing a faulty floppy controller. I doubt you would need pullups or pulldowns on the 8259, but the schematics will tell you. You should not have floating IRQ lines, they will create noise and trigger spurious interrupts. I would look closely to verify that both ends the actual are actually connected. Unless you have tri-(3-)state logic, which means that a gate can bee off, on, or ‘disconnected’. In that case, a floating line is fine, but does require that all ends are prepared for it (possibly pullup/pulldown). That said, a voltmeter is a really bad tool for this type of work. Get a logic probe with a reasonable bandwidth, it will probably cost you less than $20. And finally - IRQs may be shared, but not ‘galvanically’ (again unless you’re using tai-state logic), they must be shared via some logic, typically a OR gate.

You were right, I ended up scavenging for old PCs (which didn't use a "chipset") to see if these lines had pull ups or downs; but they didn't. In any case, having the 1K resistor on this line seems like didn't bother the card, and it works!

I have my Saleale clone and I always use it, really cool piece of kit to have. I also think the IRQs are shared on PCs, hence why it needed a pull-up (or down). I didn't see any pulls on the 8259 datasheet, but who knows!

Like @ghaerr said, put some printk's into the driver to see what’s going on with the interrupts. You can start with the #if 0 in the ne2k_int routine in ne2k.c, change it to #if 1 instead. Also, enable ethernet debug output by setting DEBUG_ETH to 1 on the debug.h file. Then you’ll immediately know when interrupts happen and what they are.

Funnyly enough, I enabled DEBUG_ETH but I don't see any debug! I had to modify that #if 0 to 1 to get some useful debug output on the IRQ handler.

For the record, I tried to ping the board IP:

$ ping 192.168.137.69
PING 192.168.137.69 (192.168.137.69) 56(84) bytes of data.
64 bytes from 192.168.137.69: icmp_seq=1 ttl=64 time=13.6 ms
64 bytes from 192.168.137.69: icmp_seq=2 ttl=64 time=13.6 ms
64 bytes from 192.168.137.69: icmp_seq=3 ttl=64 time=13.7 ms
^C
--- 192.168.137.69 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms

And this was displayed on the board's console:

8018x ELKS loader built at Fri 17 Dec 2021 02:26:29 AM -03
Now jumping into ELKS...
console_init: 8018X UART
eth: NE2K at 0x300, irq 12, MAC 00:40:05:33:ee:34
ssd: 1977614336K disk
8018X machine, 512K base RAM.
ELKS kernel 0.4.0 (44048 text, 0 ftext, 5216 data, 36896 bss, 1232 heap)
Kernel text at e062:0000, data 80:0000, top 8000:0, 467K free
VFS: Mounted root 0x0600 (romfs filesystem).
No init - running /bin/sh
# ktcp -b -p eth 192.168.137.69 192.168.137.1 255.255.255.0
ktcp: ip 192.168.137.69, gateway 192.168.137.1, netmask 255.255.255.0
ktcp: ethernet 00.40.05.33.ee.34 mtu 1500
# /1/|6664|/2/|6665|/1/|6765|/2/|6766|/1/|6866|/2/|6867|/1/|6967|/2/|6968|/1/|6b68|

I tried to run telnetd, but I got the following error once I tried to connect to it from my PC:

# telnetd
# /1/|4846|/2/|4947|/1/|4947|/2/|4948|/1/|4a48|/2/|4a49|/1/|4c49|/1/|4d4b|/2/|4f4c|/1/|4f4c|Can't create pty /dev/ptyp0

And from my machine:

$ telnet 192.168.137.69
Trying 192.168.137.69...
Connected to 192.168.137.69.
Escape character is '^]'.
Connection closed by foreign host.

I'm enabling the pseudo tty support now, and testing again!

I think I'm running really low on RAM since I get some hard locks (even tho the NE2K irqs are still coming) when running telnetd and then trying to run something else, like netstat.

This is a huge success tho, and I'm feeling really happy about it. Thank you guys for the support!

ghaerr commented 2 years ago

I enabled DEBUG_ETH but I don't see any debug!

If DEBUG_STARTDEF is 0, then you'll need to type ^P to toggle debug on to get anything.

For the record, I tried to ping the board IP:

That's fantastic, that means it seems like packets are getting received and sent!

I tried to run telnetd, but I got the following error

If /dev/ptyp0 and /dev/ttyp0 are being created on ROMFS, which I think they are, then you probably don't have CONFIG_PSEUDO_TTY set in .config.

I think I'm running really low on RAM since I get some hard locks (even tho the NE2K irqs are still coming) when running telnetd and then trying to run something else, like netstat.

Run meminfo to give you the free RAM after running telnetd.

cocus commented 2 years ago

If /dev/ptyp0 and /dev/ttyp0 are being created on ROMFS, which I think they are, then you probably don't have CONFIG_PSEUDO_TTY set in .config.

Well I enabled that, now I can connect to the board thru telnetd, but I don't have any login prompt. For every character I write on the telnet client, I get an IRQ and I see the stats being printed. Not sure what should I enable to get a login prompt.

Run meminfo to give you the free RAM after running telnetd.

No, doesn't seem I ran out of memory. Seems like it might have been something else.

EDIT: Seems like I ran something that didn't stop, and ctrl+c doesn't work :)

ghaerr commented 2 years ago

Not sure what should I enable to get a login prompt.

Your ROMFS doesn't have /bin/login, which telnetd runs when you connect, so nothing happens. The applications that are included are currently only able to specified via major category, like CONFIG_APP_SASH, CONFIG_APP_FILE_UTILS and CONFIG_APP_SH_UTILS. If you've added CONFIG_APP_KTCP, to get ktcp and telnetd, perhaps edit elkscmd/Applications and add ":net" to bin/login to get this to work.

There may be more file required in /etc (like passwd) in order for /bin/login to work. I will have to look more into this, but try experimenting and let me know what you find.

IIRC, ROMFS has a limitation of max 64K size, so things will likely be tight. We probably need to at a ":romfs" class to Applications so that you can more individually specify applications to include on the ROMFS image.

cocus commented 2 years ago

Your ROMFS doesn't have /bin/login, which telnetd runs when you connect, so nothing happens. The applications that are included are currently only able to specified via major category, like CONFIG_APP_SASH, CONFIG_APP_FILE_UTILS and CONFIG_APP_SH_UTILS. If you've added CONFIG_APP_KTCP, to get ktcp and telnetd, perhaps edit elkscmd/Applications and add ":net" to bin/login to get this to work.

Would it be possible for telnetd to run sash instead of login? I mean, I kind of don't need any of these security features right now...

IIRC, ROMFS has a limitation of max 64K size, so things will likely be tight. We probably need to at a ":romfs" class to Applications so that you can more individually specify applications to include on the ROMFS image.

Yes, I'm not sure about the size, I have APP_KTCP because it's on /bin (alongside arp, netstat, telnetd, httpd, etc). Seems like it did fit! In the worst case, I can sideload all of these apps to my sd card. It won't be the same thing, but... it has 2GB :)

Getting the SD card to auto-mount and behave like the main partition for the OS is going to be the topic for another ticket which I'll open afterwards. There's some cleanup I would like to add, like bumping the CPU frequency and the RAM size.

ghaerr commented 2 years ago

ctrl+c doesn't work :)

Strange. Your console driver runs input through tty_intcheck() so it should function. I'll bet you don't have stty to check it on ROMFS, do you? Proper handling with /bin/sash (your shell) should display a newline if you type ^C at a prompt.

Would it be possible for telnetd to run sash instead of login?

Sure, just edit elkscmd/inet/telnetd/telnetd.c and change it. (Sash is /bin/sh on your system).

ghaerr commented 2 years ago

Getting the SD card to auto-mount and behave like the main partition for the OS

That should be very straightforward: just move the (0x0200) value of the /dev/ssd SD card device into root_dev in setup.S and it will auto-mount as root at boot. It's currently set to 0x0600 (which is /dev/rom). /dev/rom isn't actually now created since it's auto-mounted at boot, so you'll need to add it into /dev by editing image/Make.devices so ROMFS can be mounted after boot.

cocus commented 2 years ago

Strange. Your console driver runs input through tty_intcheck() so it should function. I'll bet you don't have stty to check it on ROMFS, do you? Proper handling with /bin/sash (your shell) should display a newline if you type ^C at a prompt.

No, I don't have stty, and I don't see the ^C when I send a CTRL+C.

Sure, just edit elkscmd/inet/telnetd/telnetd.c and change it. (Sash is /bin/sh on your system).

I did that, and sadly I got:

HEAP: no memory (512 bytes)

Running meminfo in this condition gives me:

# meminfo
  HEAP   TYPE  SIZE    SEG   TYPE    SIZE  CNT
  a5be   SEG     16    b29   CSEG   31040    1
  a5da   BUFH   240
  a6d6   INT      6
  a6e8   INT      6
  a6fa   INT      6
  a70c   INT      6
  a71e   INT      6
  a730   TTY     80
  a78c   TTY     80
  a7e8   SEG     16   12bd   DSEG   20992    1
  a804   SEG     16   17dd   DSEG    9008    1
  a820   SEG     16   1cfd   CSEG   16800    1
  a83c   SEG     16   2117   CSEG    6224    2
  a858   SEG     16   2f97   DSEG   59392    1
  a874   SEG     16   3e17   free  269968    0
  a890   SEG     16   229c   free   20992    0
  a8ac   SEG     16   1c43   free    2976    0
  a8c8   SEG     16   1a10   DSEG    9008    1
  a8e4   SEG     16   27bc   CSEG    4560    1
  a900   SEG     16   28d9   DSEG    4448    1
  a91c   SEG     16   29ef   free   23168    0
  a938   free   330
  Heap/free    1232/  330 Total mem  478576
  Memory usage  468KB total,  158KB used,  310KB free
Mellvik commented 2 years ago

Let me join @ghaerr in congratulations, Santiago.

An impressive feat indeed.

And a word about sash: As you have noticed, it has a ^C problem. This bug has been on my list for some time. ^C at the she prompt does nothing but emit a newline. No new prompt until you actually hit a couple of newlines at the keyboard. However, when you run programs, the INTR signal is passed on to the program as it should.

I have a few other sash-issues on my list, so I'll take a look at it.

Again, great work.

--Mellvik

  1. des. 2021 kl. 06:18 skrev Santiago Hormazabal @.***>:

 Strange. Your console driver runs input through tty_intcheck() so it should function. I'll bet you don't have stty to check it on ROMFS, do you? Proper handling with /bin/sash (your shell) should display a newline if you type ^C at a prompt.

No, I don't have stty, and I don't see the ^C when I send a CTRL+C.

Sure, just edit elkscmd/inet/telnetd/telnetd.c and change it. (Sash is /bin/sh on your system).

I did that, and sadly I got:

HEAP: no memory (512 bytes) Running meminfo in this condition gives me:

meminfo

HEAP TYPE SIZE SEG TYPE SIZE CNT a5be SEG 16 b29 CSEG 31040 1 a5da BUFH 240 a6d6 INT 6 a6e8 INT 6 a6fa INT 6 a70c INT 6 a71e INT 6 a730 TTY 80 a78c TTY 80 a7e8 SEG 16 12bd DSEG 20992 1 a804 SEG 16 17dd DSEG 9008 1 a820 SEG 16 1cfd CSEG 16800 1 a83c SEG 16 2117 CSEG 6224 2 a858 SEG 16 2f97 DSEG 59392 1 a874 SEG 16 3e17 free 269968 0 a890 SEG 16 229c free 20992 0 a8ac SEG 16 1c43 free 2976 0 a8c8 SEG 16 1a10 DSEG 9008 1 a8e4 SEG 16 27bc CSEG 4560 1 a900 SEG 16 28d9 DSEG 4448 1 a91c SEG 16 29ef free 23168 0 a938 free 330 Heap/free 1232/ 330 Total mem 478576 Memory usage 468KB total, 158KB used, 310KB free — Reply to this email directly, view it on GitHub, or unsubscribe. Triage notifications on the go with GitHub Mobile for iOS or Android. You are receiving this because you were mentioned.

ghaerr commented 2 years ago

I don't see the ^C when I send a CTRL+C.

Do you mean that nothing happens at all, or that only a newline is displayed? Sash only displays a newline on ^C at the prompt, not another prompt. I suspect you mean nothing at all, which means that ^C is not being interpreted as ISIG for some reason. If you look at the 'memcpy(... &def_vals,...)' in ntty.c, that's where the original termios settings are duplicated for each tty line, which should be occurring for your serial console. Perhaps put a debug statement in your console open that tests termios.c_lflag & ISIG, or put the check in tty_intcheck().

sadly I got: HEAP: no memory (512 bytes)

When telnetd opens a pty, 512 bytes are allocated in the kernel for its buffer. Notice in the meminfo display above, there are only 330 free of 1232 bytes available in the kernel heap. That's why you're getting the message.

Recall when we started the 8081X port, you were running only 128K ram. The system heap was then set in config.h to a very minimal value of 128, using SETUP_HEAPSIZE. You can either increase that a bit, or just comment it out, in which case the kernel heap will automatically be set to the end of the 64K kernel data segment.

I also notice in config.h that CONFIG_MEM_KBYTES is set to 128. Is your version at 512? This should match system memory. If it's set to 128, but meminfo is reporting total mem of 478576, then we have a bug.

ghaerr commented 2 years ago

Would it be possible for telnetd to run sash instead of login? I mean, I kind of don't need any of these security features right now...

telnetd could be easily modified to exec /bin/sh if /bin/login doesn't exist... that would open a security hole, but would make it usable on smaller systems without adding more config options. Or perhaps just do this if CONFIG_ROMFS_FS is set? @Mellvik, do you have thoughts on this?

Mellvik commented 2 years ago

Santiago, @ghaerr,

I'm fine with this. There are many user level open doors in ELKS, for good reasons. That said, whenever we or someone decides tro make it more secure, that will indeed be possible. So having telnetd fork off /bin/sash should be OK - unless there are environment dependencies that I'm not aware of. And Yes, making that the default for really small configurations is a good idea. Lowers the threshold to get going.

As to sash and ^C, I'll comment on that in the PR thread. (#1061)

—M

  1. des. 2021 kl. 17:16 skrev Gregory Haerr @.***>:

Would it be possible for telnetd to run sash instead of login? I mean, I kind of don't need any of these security features right now...

telnetd could be easily modified to exec /bin/sh if /bin/login doesn't exist... that would open a security hole, but would make it usable on smaller systems without adding more config options. Or perhaps just do this if CONFIG_ROMFS_FS is set? @Mellvik https://github.com/Mellvik, do you have thoughts on this?

— Reply to this email directly, view it on GitHub https://github.com/jbruchon/elks/issues/1017#issuecomment-998071204, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA3WGOGU2XW3QTBHUATZZDTUR5JHFANCNFSM5IOQGRPA. Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub. You are receiving this because you were mentioned.

cocus commented 2 years ago

I also notice in config.h that CONFIG_MEM_KBYTES is set to 128. Is your version at 512? This should match system memory. If it's set to 128, but meminfo is reporting total mem of 478576, then we have a bug.

Yes, when I updgraded my board to have 512k of ram, I changed this value. That's what I was referring in my last comment about the cleanup. I want to open a new PR with these changes, and probably commenting out the SETUP_HEAPSIZE so it's dynamic.

Let me join @ghaerr in congratulations, Santiago. An impressive feat indeed.

Thank you! I would like to document my hardware mods so this can be done by anyone willing to spend some time with a solder iron :)

As a side note, would it be possible to have a menuconfig to select if you want to use the 16 or 8 bit variant of the ne2k driver? If I recall correctly, NCommander mentioned that on FreeBSD there was a config to do exactly this. This config + some ifdefs on the assembly code should do the trick.

Do you mean that nothing happens at all, or that only a newline is displayed? Sash only displays a newline on ^C at the prompt, not another prompt. I suspect you mean nothing at all, which means that ^C is not being interpreted as ISIG for some reason. If you look at the 'memcpy(... &def_vals,...)' in ntty.c, that's where the original termios settings are duplicated for each tty line, which should be occurring for your serial console. Perhaps put a debug statement in your console open that tests termios.c_lflag & ISIG, or put the check in tty_intcheck().

Absolutely nothing. No newline, no ^C, no nothing. However, it goes to some buffer, because if I hit CTRL+C and then enter, it says that the command was too complex.

I will debug this a little bit further today, adding these console debug stuff.

I'm fine with this. There are many user level open doors in ELKS, for good reasons. That said, whenever we or someone decides tro make it more secure, that will indeed be possible. So having telnetd fork off /bin/sash should be OK - unless there are environment dependencies that I'm not aware of. And Yes, making that the default for really small configurations is a good idea. Lowers the threshold to get going.

Agreed. Just a small thought, if there's no "login" binary, I highly suspect there's no intention (or maybe space on the rootfs) of using users.

ghaerr commented 2 years ago

Yes, when I updgraded my board to have 512k of ram, I changed this value. That's what I was referring in my last comment about the cleanup. I want to open a new PR with these changes, and probably commenting out the SETUP_HEAPSIZE so it's dynamic.

Great, go ahead. It will be nice to sync up master with your version.

I would like to document my hardware mods so this can be done by anyone willing to spend some time with a solder iron :)

You're welcome to open a wiki page describing your hardware mods :)

As a side note, would it be possible to have a menuconfig to select if you want to use the 16 or 8 bit variant of the ne2k driver? If I recall correctly, NCommander mentioned that on FreeBSD there was a config to do exactly this. This config + some ifdefs on the assembly code should do the trick.

Sure. Go ahead and add that to elks/arch/i86/drivers/net/config.in, or let me know and I will. We could use CONF_ETH_BYTE_ACCESS or something like that; any network drivers would use 8 bit access if set.

No newline, no ^C, no nothing. However, it goes to some buffer, because if I hit CTRL+C and then enter, it says that the command was too complex.

That just means that ^C (0x03) was entered into the command buffer, and that ISIG is not working. Perhaps check the code in tty_intcheck, as that function throws the signal. You can turn on DEBUG_SIGNAL and DEBUG_TTY to see it all in action

Just a small thought, if there's no "login" binary, I highly suspect there's no intention (or maybe space on the rootfs) of using users.

Ok, I'll add that change in a separate PR.

cocus commented 2 years ago

Sure. Go ahead and add that to elks/arch/i86/drivers/net/config.in, or let me know and I will. We could use CONF_ETH_BYTE_ACCESS or something like that; any network drivers would use 8 bit access if set.

I've added it as CONFIG_ETH_NE2K_BYTE_ACCESS since I don't know if this is also applicable to the WD card; and even so, I don't know what should I change in its driver.

Ok, I'll add that change in a separate PR.

Excellent!

Great, go ahead. It will be nice to sync up master with your version.

That's coming after the byte access ne2k PR.

Thanks!

ghaerr commented 2 years ago

I've added it as CONFIG_ETH_NE2K_BYTE_ACCESS since I don't know if this is also applicable to the WD card

I would prefer using CONFIG_ETH_BYTE_ACCESS, as then when the WD card gets updated for byte access, we won't have to keep two versions of the configuration name. (Leaving the network adaptor name out of the option allows it to be used by more than one driver if needed).

Thank you!

cocus commented 2 years ago

I would prefer using CONFIG_ETH_BYTE_ACCESS, as then when the WD card gets updated for byte access, we won't have to keep two versions of the configuration name. (Leaving the network adaptor name out of the option allows it to be used by more than one driver if needed).

No problem!

Hey I found a bug with the latest code. First of all, the TIMER_IRQ is not defined on ports.h, which is fine, and I can add a PR to address this. Second, peekpoke.S is using SETUP_DATA which gets set to REL_INTSEG because there's a rogue #define SETUP_DATA on line 115 of config.h :(. There's some stuff missing, like DEF_OPTSEG used by boot_minix.c, call_bios used by fdtest.c. Do you want me to open a new issue to talk about these?

ghaerr commented 2 years ago

First of all, the TIMER_IRQ is not defined on ports.h, which is fine, and I can add a PR to address this.

Yes, I moved some PC-related stuff out of timer-8254.c into ports.h for the PC-98 port. However, I'm trying to get rid of ports.h, certainly for your 8081X port. Can you put that definition in 8018x.h and not include ports.h?

Second, peekpoke.S is using SETUP_DATA which gets set to REL_INTSEG because there's a rogue #define SETUP_DATA on line 115 of config.h :(

Oops! Let me fix this up right now. I will move SETUP_DATA as an "#else" to CONFIG_ROMCODE and figure out the other problems.

cocus commented 2 years ago

Yes, I moved some PC-related stuff out of timer-8254.c into ports.h for the PC-98 port. However, I'm trying to get rid of ports.h, certainly for your 8081X port. Can you put that definition in 8018x.h and not include ports.h?

I can, but it's used on irq.c; not on my 8018x specific code. I've added the following to ports.h:

#ifdef CONFIG_ARCH_8018X
#define TIMER_IRQ   0       /* logical IRQ number, NOT related to the actual IRQ vector! */
#endif

Oops! Let me fix this up right now. I will move SETUP_DATA as an "#else" to CONFIG_ROMCODE and figure out the other problems.

Please note that I've edited my previous comment since I found some other issues as well.

Thanks

ghaerr commented 2 years ago

I can, but it's used on irq.c; not on my 8018x specific code. I've added the following to ports.h:

Ok, you're right. Keep that change in there. We'll sort this out a bit more later.

Please note that I've edited my comment since I found some other issues as well.

Testing compilations now. Thanks for the heads up!

cocus commented 2 years ago

Excellent! Well, I have a question now. Since we began working on the 8018x port, I didn't specify anything related to the hardware itself, since the UART and Timer are inside the CPU. Now, this network change requires some additional hardware (in my case it was a 74ls139, but in theory it could be an OR gate or some other combinational logic) and the usage of a specific INT pin of the CPU (all of the 4 INT pins could have been used, but INT1 was the one I had traced and it was readily available). In theory whoever uses this port could change which INT pin is used by modifying the irq-8018x.c. So I assume I could push my changes, but they're not as generic as I would like. What do you think? Also, what about the .config defaults for this platform? Should I leave the ne2k out of it?

ghaerr commented 2 years ago

In theory whoever uses this port could change which INT pin is used by modifying the irq-8018x.c. So I assume I could push my changes, but they're not as generic as I would like.

Rather than pushing specific changes, I feel it would be better for the 8018X ELKS port to have a more generic approach to interrupt management, rather than modifying a .c file for each use case. Even better would be fleshing out each of the pin numbers and/or addresses in a .h file, and best would be scheme using "logical" IRQ numbers that get translated to actual interrupt vectors, as suggested in https://github.com/jbruchon/elks/pull/1074#issue-1087342107. So - don't push your immediate changes, but create a longer-lasting mechanism for yourself and future 8018X users.

Also, what about the .config defaults for this platform? Should I leave the ne2k out of it?

Contrary to above, for testing, it's nice to have a contributor's actual .config file (in this case 8018x.config) that exactly matches the largest working subset of kernel features that have been used. This allows myself or others to recreate the environment for regression tests, as well as having at least one specific known-working configuration file. So - NE2K should be in, and push that up with your next PR!

cocus commented 2 years ago

Rather than pushing specific changes, I feel it would be better for the 8018X ELKS port to have a more generic approach to interrupt management, rather than modifying a .c file for each use case. Even better would be fleshing out each of the pin numbers and/or addresses in a .h file, and best would be scheme using "logical" IRQ numbers that get translated to actual interrupt vectors, as suggested in #1074 (comment). So - don't push your immediate changes, but create a longer-lasting mechanism for yourself and future 8018X users.

For this to work, I think all (or most) IRQ numbers should be configurable from the menuconfig and have their defaults set to the current values set on the ports.h. If we manage to configure IRQs via menuconfig, then I can piggyback that concept and create a set of configuration entries for each INT pin that maps to one of those "logical" IRQ numbers. For my particular use case, I could set INT1 to use IRQ 3 :) (I'll leave all the other internal-peripheral's IRQs non-configurable tho, because these won't make any sense to be modified). I think I could start by adding a mechanism to select which "logical" IRQ maps to which INT pin via menuconfig; and then we can talk about transitioning hardcoded IRQ numbers to config on the menuconfig. What do you think?

EDIT: I was trying the following for the config:

    elif [ "$CONFIG_ARCH_8018X" = "y" ]; then

        comment 'Devices'

        comment 'INTx pins'
        bool 'INT0'     CONFIG_8018X_INT0_ENABLED   n
        if [ "$CONFIG_8018X_INT0_ENABLED" = "y" ]; then
            int 'INT0 Logical IRQ' CONFIG_8018X_INT0 11
        fi
        bool 'INT1'     CONFIG_8018X_INT1_ENABLED   y
        if [ "$CONFIG_8018X_INT1_ENABLED" = "y" ]; then
            int 'INT1 Logical IRQ' CONFIG_8018X_INT1 12
        fi
        bool 'INT2'     CONFIG_8018X_INT2_ENABLED   n
        if [ "$CONFIG_8018X_INT2_ENABLED" = "y" ]; then
            int 'INT0 Logical IRQ' CONFIG_8018X_INT2 13
        fi
        bool 'INT3'     CONFIG_8018X_INT3_ENABLED   n
        if [ "$CONFIG_8018X_INT3_ENABLED" = "y" ]; then
            int 'INT0 Logical IRQ' CONFIG_8018X_INT3 14
        fi
        bool 'INT4'     CONFIG_8018X_INT4_ENABLED   n
        if [ "$CONFIG_8018X_INT4_ENABLED" = "y" ]; then
            int 'INT0 Logical IRQ' CONFIG_8018X_INT4 10
        fi

Contrary to above, for testing, it's nice to have a contributor's actual .config file (in this case 8018x.config) that exactly matches the largest working subset of kernel features that have been used. This allows myself or others to recreate the environment for regression tests, as well as having at least one specific known-working configuration file. So - NE2K should be in, and push that up with your next PR!

Okay, I can do that!

ghaerr commented 2 years ago

Hello @cocus,

I think I could start by adding a mechanism to select which "logical" IRQ maps to which INT pin via menuconfig; and then we can talk about transitioning hardcoded IRQ numbers to config on the menuconfig. What do you think?

I like it! But only for the 8018X for the time being.

How about we start with your config.in changes above for the 8081X port only, and see what you come up with, and delay any IBM PC/desktop changes until after v.0.5.0? Agreed it could be a big benefit to map IRQ numbers, but it seems the 8018X very much needs this, as the interrupt numbers are hard-coded possibly differently depending on the chip and would immediately benefit from logical interrupt numbers, while the IBM PC/desktop interrupt numbers are not so much mapped to logical interrupts, but external physical cards. We will need to think a bit more about IBM PC logical interrupt numbers and logical "devices" without confusing users trying to get ELKS setup.

In any case, I would prefer to delay opening the potential messiness of this on desktop, while for your port, I'll accept a PR when you have it working at anytime. Your version shouldn't have to deal with anything in ports.h, but instead only 8018x.h. We can then look further into the implementation after you've got it posted.

Thank you!

cocus commented 2 years ago

Hi @ghaerr, as usual, I was really busy and didn't have enough time to tinker with this. I was also working on creating an SBC with the same 80C188 I'm currently using, similar configuration and IO, but it'll contain an ISA slot ready to go. ELKS should work as-is on it, assuming it works :) Now, getting back to this topic, I have my changes that will let you select which INT pins you are using, and to which logical IRQ they'll map. For instance, the NE2K (in 1K mode) card I have it's connected to the INT1 pin, and it's using the logical IRQ 12. Thus I can enable the usage of INT1, and input "12" as the logical IRQ for that INT1 pin I've enabled. These changes are on config.in; as we've discussed before. This is then used on the irq-8018x.c, where using #ifedefs I add additional elements to a logical IRQ array:

struct irq_logical_map {
    unsigned int irq;           /* logical IRQ from ELKS */
    unsigned int config_word;   /* config word for the Interrupt control register */
    unsigned int pcb_register;  /* interrupt control register on the PCB */
    int irq_vector;             /* CPU IRQ Vector number */
} logical_map[] = {
    /* 8018x: Timer Interrupt unmasked, priority 7, Interrupt type (vector) 18. */
    { TIMER_IRQ, 0x7, PCB_TCUCON, CPU_VEC_TIMER1 },
    /**
     * 8018x: Enabling Serial Interrupts will enable the RX and TX IRQs
     * at the same time, this is a CPU limitation.
     * Serial Interrupts unmasked, priority 1, Interrupt type (vector) 20 and 21.
     */
    { UART0_IRQ_RX, 0x1, PCB_SCUCON, CPU_VEC_S0_RX },
    { UART0_IRQ_TX, 0x1, PCB_SCUCON, CPU_VEC_S0_TX },
#ifdef CONFIG_8018X_INT0_ENABLED
    { CONFIG_8018X_INT0, 0x6, PCB_I0CON, CPU_VEC_INT0 },
#endif
#ifdef CONFIG_8018X_INT1_ENABLED
    { CONFIG_8018X_INT1, 0x6, PCB_I1CON, CPU_VEC_INT1 },
#endif
#ifdef CONFIG_8018X_INT2_ENABLED
    { CONFIG_8018X_INT2, 0x6, PCB_I2CON, CPU_VEC_INT2 },
#endif
#ifdef CONFIG_8018X_INT3_ENABLED
    { CONFIG_8018X_INT3, 0x6, PCB_I3CON, CPU_VEC_INT3 },
#endif
#ifdef CONFIG_8018X_INT4_ENABLED
    { CONFIG_8018X_INT4, 0x6, PCB_I4CON, CPU_VEC_INT4 },
#endif
};

struct irq_logical_map* get_from_logical_irq(unsigned int irq)
{
    size_t i;
    for (i = 0; i < (sizeof(logical_map)/sizeof(logical_map[0])); ++i)
    {
        if (logical_map[i].irq == irq)
        {
            return &logical_map[i];
        }
    }

    return NULL;
}

Then, for the enable_irq and irq_vector I've used the get_from_logical_irq function to look up this array and grab the proper element for all IRQs (which previously were hardcoded, like the timer 1 and uart rx and tx):


void enable_irq(unsigned int irq)
{
    struct irq_logical_map* map;
    map = get_from_logical_irq(irq);
    if (map) {
        outw(map->config_word, map->pcb_register);
    }
}

// Get interrupt vector from IRQ
int irq_vector(int irq)
{
    struct irq_logical_map* map;

    map = get_from_logical_irq(irq);
    if (map) {
        return map->irq_vector;
    }

    return -EINVAL;
}

Do you think I should change something for the upcoming PR?

Thanks!

cocus commented 2 years ago

Besides my changes to the INT stuff, with the current elks 0.5.0 I can't run telnetd without the system completely hanging on me! Did I run out of memory?

8018x ELKS loader built at Fri 01 Apr 2022 05:53:34 PM -03
Now jumping into ELKS...
console_init: 8018X UART
eth: NE2K at 0x300, irq 12, MAC 00:40:05:33:ee:34
ssd: 1977614336K disk
8018X machine, 512K base RAM.
ELKS kernel 0.5.0 (45056 text, 0 ftext, 5312 data, 37984 bss, 22238 heap)
Kernel text at e062:0000, data 80:0000, top 8000:0, 446K free
VFS: Mounted root 0x0600 (romfs filesystem).
No init - running /bin/sh
# meminfo
  HEAP   TYPE  SIZE    SEG   TYPE    SIZE  CNT
  a92e   SEG     16   1080   CSEG   31408    1
  a94a   INT      6
  a95c   INT      6
  a96e   INT      6
  a980   INT      6
  a992   BUFH   216
  aa76   INT      6
  aa88   TTY     80
  aae4   TTY     80
  ab40   SEG     16   182b   DSEG   21008    1
  ab5c   SEG     16   1d4c   free   21008    0
  ab78   SEG     16   226d   CSEG    4096    1
  ab94   SEG     16   236d   DSEG    2448    1
  abb0   SEG     16   2406   free  376736    0
  abcc   free 21556
  Heap/free   22238/21556 Total mem  456704
  Memory usage  446KB total,   58KB used,  388KB free
# n
ktcp: ip 192.168.137.69, gateway 192.168.137.1, netmask 255.255.255.0
ktcp: ethernet 00.40.05.33.ee.34 mtu 1500
# meminfo
  HEAP   TYPE  SIZE    SEG   TYPE    SIZE  CNT
  a92e   SEG     16   1080   CSEG   31408    1
  a94a   INT      6
  a95c   INT      6
  a96e   INT      6
  a980   INT      6
  a992   BUFH   216
  aa76   INT      6
  aa88   TTY     80
  aae4   TTY     80
  ab40   SEG     16   182b   DSEG   21008    1
  ab5c   SEG     16   1d4c   free   21008    0
  ab78   SEG     16   226d   CSEG   18464    1
  ab94   SEG     16   26ef   CSEG    4096    1
  abb0   SEG     16   3510   DSEG   57872    1
  abcc   SEG     16   4331   free  249072    0
  abe8   SEG     16   27ef   DSEG    2448    1
  ac04   SEG     16   2888   free   51328    0
  ac20   free 21472
  Heap/free   22238/21472 Total mem  456704
  Memory usage  446KB total,  132KB used,  314KB free
# telnetd

Well, seems like this is intermittent. I can reboot the system and try again and it just works... telnetd doesn't hangs the system, although it refuses my connections to it. I'm reviewing what's going on. Seems related to #define _PATH_BSHELL "/bin/sh" on paths.h

ghaerr commented 2 years ago

Hello @cocus, nice to see you here again! :)

Do you think I should change something for the upcoming PR?

Your 8018x IRQ enhancements look good. My only comment would be it would be nice if we could find a way to have less CONFIG_8018X_xxx defines, if possible? For instance, in:

#ifdef CONFIG_8018X_INT0_ENABLED
    { CONFIG_8018X_INT0, 0x6, PCB_I0CON, CPU_VEC_INT0 },
#endif
...

I haven't seen your config.in, but would it be possible to have CONFIG_8018X_INT0 be used directly, rather than with a seperate ..._INT0_ENABLED, perhaps just using it's value, something like the following, where the value would be set to -1 to turn the interrupt off? (I'm not sure how much effort you've already placed into config.in, but I've found that in general, we already have too many CONFIG_xxx flags):

#ifdef CONFIG_8018X_INT0
    { CONFIG_8018X_INT0, 0x6, PCB_I0CON, CPU_VEC_INT0 },
#endif
ghaerr commented 2 years ago

I can't run telnetd without the system completely hanging on me! Did I run out of memory?

It doesn't seem so - but telnetd does fork() to become a daemon, which fragments memory further, in the last 249k chunk of memory.

Do you get a prompt back after running telnetd? It forks to become a daemon, then the shell should issue another prompt; I don't see that happening. This should all happen way prior to it accepting any connection requests. That is, you should be able to run meminfo after running telnetd to see how much is remaining. Also perhaps try running telnetd prior to running ktcp, just to make sure it exits properly with an error message. This will also let you use meminfo to see whether running it fragments more memory.

Do you have the file /etc/perror on ROMFS? That is required for the perror() message to appear if telnetd is having a problem.

cocus commented 2 years ago

I haven't seen your config.in, but would it be possible to have CONFIG_8018X_INT0 be used directly, rather than with a seperate ..._INT0_ENABLED, perhaps just using it's value, something like the following, where the value would be set to -1 to turn the interrupt off? (I'm not sure how much effort you've already placed into config.in, but I've found that in general, we already have too many CONFIG_xxx flags):

Yes, setting it to -1 would be a good idea... Or 0. Is it possible to cap the span of the integer value the user can input on lxdialog?

My confi.in looks like:

    elif [ "$CONFIG_ARCH_8018X" = "y" ]; then

        comment 'Devices'

        comment 'INTx pins'
        bool 'INT0'     CONFIG_8018X_INT0_ENABLED   n
        if [ "$CONFIG_8018X_INT0_ENABLED" = "y" ]; then
            int 'INT0 Logical IRQ' CONFIG_8018X_INT0 11
        fi
        bool 'INT1'     CONFIG_8018X_INT1_ENABLED   n
        if [ "$CONFIG_8018X_INT1_ENABLED" = "y" ]; then
            int 'INT1 Logical IRQ' CONFIG_8018X_INT1 12
        fi
        bool 'INT2'     CONFIG_8018X_INT2_ENABLED   n
        if [ "$CONFIG_8018X_INT2_ENABLED" = "y" ]; then
            int 'INT0 Logical IRQ' CONFIG_8018X_INT2 13
        fi
        bool 'INT3'     CONFIG_8018X_INT3_ENABLED   n
        if [ "$CONFIG_8018X_INT3_ENABLED" = "y" ]; then
            int 'INT0 Logical IRQ' CONFIG_8018X_INT3 14
        fi
        bool 'INT4'     CONFIG_8018X_INT4_ENABLED   n
        if [ "$CONFIG_8018X_INT4_ENABLED" = "y" ]; then
            int 'INT0 Logical IRQ' CONFIG_8018X_INT4 10
        fi

But I could technically just rely on the CONFIG_8018X_INTx (with x=0...4) and use that with the #if statements on the irq driver. What do you think?

Do you get a prompt back after running telnetd? It forks to become a daemon, then the shell should issue another prompt; I don't see that happening. This should all happen way prior to it accepting any connection requests. That is, you should be able to run meminfo after running telnetd to see how much is remaining. Also perhaps try running telnetd prior to running ktcp, just to make sure it exits properly with an error message. This will also let you use meminfo to see whether running it fragments more memory.

When it "works" I do get the prompt back, but when it doesn't, I don't get it back!

I've also experienced that a single connected telnet client might hang, but I can still use the serial console without any issues. Killing the sash and the telnetd fork kills the connection, but these are still shown as zombies. Maybe this is something to consider on a new ticket? I bet it's something on my board or a corner case of this machine.

ghaerr commented 2 years ago

I could technically just rely on the CONFIG_8018X_INTx (with x=0...4) and use that with the #if statements on the irq driver.

If you displayed "INTx pins (0=off)" above, then just accepted input of 0-... in each box, that should work fine. Then, the following #if check could be used in C which would protect against an undefined or 0 value. (The "+ 0" allows compilation to proceed even if the preprocessor symbol is not defined):

#if CONFIG_8018X_INT0 + 0 > 0
    { CONFIG_8018X_INT0, 0x6, PCB_I0CON, CPU_VEC_INT0 },
#endif

When it "works" I do get the prompt back, but when it doesn't, I don't get it back!

I would guess that when you don't get the prompt back the system has crashed, since the shell should prompt back regardless of what telnetd might be doing after its fork, unless the interaction of telnets's listen and accept calls are crashing the system for some reason. Perhaps try an outbound telnet after ktcp, without running telnetd and see what happens (both with and without a connect).

I've also experienced that a single connected telnet client might hang, but I can still use the serial console without any issues. Killing the sash and the telnetd fork kills the connection, but these are still shown as zombies. Maybe this is something to consider on a new ticket? I bet it's something on my board or a corner case of this machine.

I'm not sure the need to open a new ticket just yet, but if there has been any network activity, this could be a problem with interrupts or otherwise with your fancily-connected NIC! :)

cocus commented 2 years ago

If you displayed "INTx pins (0=off)" above, then just accepted input of 0-... in each box, that should work fine. Then, the following #if check could be used in C which would protect against an undefined or 0 value. (The "+ 0" allows compilation to proceed even if the preprocessor symbol is not defined):

#if CONFIG_8018X_INT0 + 0 > 0
    { CONFIG_8018X_INT0, 0x6, PCB_I0CON, CPU_VEC_INT0 },
#endif

Okay, that makes sense. I'll open a PR with these changes.

I've also experienced that a single connected telnet client might hang, but I can still use the serial console without any issues. Killing the sash and the telnetd fork kills the connection, but these are still shown as zombies. Maybe this is something to consider on a new ticket? I bet it's something on my board or a corner case of this machine.

I'm not sure the need to open a new ticket just yet, but if there has been any network activity, this could be a problem with interrupts or otherwise with your fancily-connected NIC! :)

Well, I don't think so. I've enabled a nice printk on my uart when I receive a ctrl c (i.e. char = 0x03) and I still get these. Funny that no app I've ran dies when I send that :(. In any case, I've also enabled a small printk which'll print "N" whenever there's a network card interrupt, and I do see them coming... Really weird...

As a side note, I'm trying to port "any C implementation of basic" to ELKS and all of them (the ones that I consider a little bit more than a prototype) always fail to malloc() stuff. I don't think they're even malloc-ing that much, but I still get errors like sys_brk(2) fail: brk 282c over by 460 bytes. I'd like to grow the heap or something so these apps don't fail, because I'll end up showing up this ELKS board and I want a basic interpreter running :)

Thanks!

ghaerr commented 2 years ago

I'm trying to port "any C implementation of basic" to ELKS

Cool - I have been thinking for a while about doing the same myself. Do you have any favorites?

I'd like to grow the heap or something so these apps don't fail

The default heap is 4K bytes for ELKS programs (and 4K bytes for stack). To increase the heap, use -maout-heap= in the link line in the Makefile. To set max heap, use -maout-heap=0ffff. (The heap and stack sizes are statically allocated by the kernel on program startup, for various reasons on the 8086).

cocus commented 2 years ago

Cool - I have been thinking for a while about doing the same myself. Do you have any favorites?

Sadly I haven't. I've tried some:

ghaerr commented 2 years ago

except the one from jwillia3, where I did use 65534 instead of 0ffff because it errored out about a negative number.

I'd like to see that error message, as both 65534 (0xfffe) and 0xffff would be interpreted as "negative" if the other were. However, using each have completely different effects, FYI. If the heap value is set to 0xffff, then ELKS will load the executable and give it the maximum size heap possible, which would be (64K - sizeof(stack) - sizeof(BSS) - sizeof(DATA)). Setting the heap to any other value forces the heap to that value, and, if not possible due to not enough heap available, will refuse to load the executable. I would imagine the latter is what would happen if -maout-heap=65534 is given.

I think the minimum requirement for this would be to have string variables, because integer variables are kinda boring. I don't necessarily need floating point arithmetic, but would be nice to have (if it doesn't use that much space).

I have some favorites, let me see where I might have put them :)

cocus commented 2 years ago

I'd like to see that error message, as both 65534 (0xfffe) and 0xffff would be interpreted as "negative" if the other were. However, using each have completely different effects, FYI. If the heap value is set to 0xffff, then ELKS will load the executable and give it the maximum size heap possible, which would be (64K - sizeof(stack) - sizeof(BSS) - sizeof(DATA)). Setting the heap to any other value forces the heap to that value, and, if not possible due to not enough heap available, will refuse to load the executable. I would imagine the latter is what would happen if -maout-heap=65534 is given.

ia16-elf-gcc -fno-inline -melks-libc -mcmodel=small -mno-segment-relocation-stuff -mtune=i8086 -Wall -Os -maout-heap=0ffff -o nanobasic arch.o array.o dictionary.o error.o hexdump.o io.o kbhit.o lines.o main.o parser.o tokenizer.o variables.o
ia16-elf-gcc: error: argument to ‘-maout-heap=’ should be a non-negative integer

I forgot to add the 0x to the new argument. Setting it to 0ffff hits that error, but 0x0ffff doesn't. Didn't know about that.

cocus commented 2 years ago

I've opened https://github.com/jbruchon/elks/pull/1244. In the meantime, I did started chasing the issue with the ^C not working on my platform. I've checked and I do receive the 0x03 character, and I've hacked ntty.c so it uses 0x03 instead of ttyp->termios.c_cc[VINTR]. I've also added code on the 8018x serial driver so it prints out ^C each time 0x03 is received, and I do see it, but NO response from any app. For instance, I've connected to the Start Wars telnet "movie" (telnet towel.blinkenlights.nl) and I see the ascii movie, but I can't stop it. Other apps, like nslookup also don't stop when I hit that... I remember you @ghaerr and @Mellvik were discussing this in the past, but I don't recall what was the outcome... In any case, I'm open to your suggestions, since I'd like to be able to just stop any given app instead of hard-rebooting my system.

ghaerr commented 2 years ago

I looked at all these interpreters and it seems ubasic is too small with no strings support, nanoflight is huge and the first one's documentation is written in chinese. The jwillia3 version looks good, but it needs a few changes in order to run on ELKS, the biggest one being the default program size is 64K, obviously too large for ELKS.

I have that version running, with their PR 2 (https://github.com/jwillia3/BASIC/pull/2) applied to clean things up. However, that PR has a major bug in it which prevents "test.txt" to run. Apply this patch and you should be good to go for an ELKS port:

diff --git a/basic.h b/basic.h
index ad7d3b3..b5b0d4c 100755
--- a/basic.h
+++ b/basic.h
@@ -6,7 +6,7 @@
 #include <string.h>
 #include <stdint.h>
 #define SYMSZ  16                      /* SYMBOL SIZE */
-#define PRGSZ  65536                   /* PROGRAM SIZE */
+#define PRGSZ  8192                    /* PROGRAM SIZE */
 #define STKSZ  256                     /* STACK SIZE */
 #define STRSZ  4096                    /* STRING TABLE SIZE */
 #define VARS   512                     /* VARIABLE COUNT */
@@ -104,7 +104,7 @@ int  RV_(void) { *--sp=ret; STEP; }
 int  DROP_(void) { sp+=PCV; STEP; }
 int  DIM_(void) { int v=PCV, n=*sp++; Val *mem=calloc(sizeof(Val),n+1);
        mem[0]=n; value[v]=(Val)mem;
-       return 0;
+       STEP;
 }
 int  LOADI_(void) { Val x=*sp++; x=*bound((Val*)value[PCV],x); *--sp=x; STEP; }
 int  STOREI_(void) { Val x=*sp++, i=*sp++; *bound((Val*)value[PCV],i)=x; STEP; }
ghaerr commented 2 years ago

I've connected to the Start Wars telnet "movie" (telnet towel.blinkenlights.nl) and I see the ascii movie, but I can't stop it.

It is possible that telnet isn't processing ^C properly, as well as having some buffering, so this isn't a good test.

Other apps, like nslookup also don't stop when I hit that...

When ^C is typed and you're running the ash shell (large /bin/sh, not sash, which can be sometimes installed as /bin/sh instead of /bin/sash), a linefeed should be displayed and you get a new prompt.

In order to debug what might be happening, do two things: turn on DEBUG_SIGNAL and DEBUG_TTY in include/debug.h, and then type ^P to turn on and off kernel signal debug info. You should see lots of kernel activity when you type ^C with debug signals on.

The following code sends a SIGINT to the shell process group in drivers/char/ntty.c:

int tty_intcheck(register struct tty *ttyp, unsigned char key)
{
    sig_t sig = 0;

    if ((ttyp->termios.c_lflag & ISIG) && ttyp->pgrp) {
        if (key == ttyp->termios.c_cc[VINTR])
            sig = SIGINT;
        if (key == ttyp->termios.c_cc[VSUSP])
            sig = SIGTSTP;
#if DEBUG_EVENT
        if (key == ('P' & 0x1f)) {      /* ctrl-P*/
            debug_event();
            return 1;
        }
#endif
        if (sig) {
            debug_tty("TTY signal %d to pgrp %d pid %d\n", sig, ttyp->pgrp, current->pid);
            kill_pg(ttyp->pgrp, sig, 1);
        }
    }
    return sig;
}

Do a ps and make sure that the /bin/sh entry has the same PID and GRP. Otherwise, the kill_pg (kill to process group) may not be working. With DEBUG_SIGNAL and DEBUG_TTY on, you should see the kernel printk just before calling kill_pg, along with the kernel's generation of the signal to the shell process. You can continue to trace/read about the signal being generated a bit more by looking at kill_pg in elks/kernel/signal.c.

Sorry to drag you through all this, but without the debug info, I can't tell whether the signal is being generated or not, which is the first big thing.

cocus commented 2 years ago

It is possible that telnet isn't processing ^C properly, as well as having some buffering, so this isn't a good test.

This actually works fine when I telnet into the board, and then run the telnet command to the remote host. I can ^C properly.

When ^C is typed and you're running the ash shell (large /bin/sh, not sash, which can be sometimes installed as /bin/sh instead of /bin/sash), a linefeed should be displayed and you get a new prompt.

If I'm not mistaken, I have sash installed, and I don't get a linefeed when I ^C. In fact, if I ^C from the serial console, I get:

# ^C
Not supported by standalone shell: ''

(Note: I hit enter after the ^C, and that was printed by the serial code when 0x03 is received). Now, from the telnet console, I do get a line feed when I ^C, and I also get some verbose output on the serial console: TTY signal 2 to pgrp 9 pid 8

In order to debug what might be happening, do two things: turn on DEBUG_SIGNAL and DEBUG_TTY in include/debug.h, and then type ^P to turn on and off kernel signal debug info. You should see lots of kernel activity when you type ^C with debug signals on.

I don't see ANYTHING if I do ^C from the serial console, but I do see some output on the serial console if I ^C on the telnet console:

# ps ax
  PID   GRP  TTY USER STAT CSEG DSEG  HEAP   FREE   SIZE COMMAND
    1     0      root    S 1080 182b  1314   6534  52416 /bin/sash 
    8     7      root    S 26ef 1f82     0   1956  15600 telnetd 
    5     5      root    S 226d 3510  5806  29956  76336 ktcp -b -p eth 192.168.137.69 192.168.137.1 255.255.255.0 
    7     7      root    S 26ef 1d4c     0   2008  15600 telnetd 
    9     9   p0 root    S 1080 2abe  1262   7746  52464 /bin/sash 
   13     0      root    R 2888 4331  1024   1194  11008 ps ax 
# <- 0000: 03                                                .
TTY signal 2 to pgrp 9 pid 8
-> 0000: 0d 0a                                             ..
-> 0000: 23 20                                             

Sorry to drag you through all this, but without the debug info, I can't tell whether the signal is being generated or not, which is the first big thing.

Yeah, no worries. I think there's NO signal at all... Maybe this is related to the way the 8018x serial console is implemented?

ghaerr commented 2 years ago

Hello @cocus,

Do a ps and make sure that the /bin/sh entry has the same PID and GRP

On a standard ELKS PC floppy image, I just erased /bin/init and then rebooted, here's what I got:

Screen Shot 2022-04-03 at 9 54 42 PM

What do you know, the shell process group is 0, and ^C doesn't work! So that's the problem.

A quick hack would be to remove the check for non-zero ttyp->pgrp in the above-referenced code in drivers/char/ntty.c, as it's now obvious that the reason ^C isn't working is for this reason. What needs to happen is a call to sys_setsid() to set the process group, which /bin/init does but the shell does not. Let me take a quick look into this.