I have a motherboard which has a Nuvoton W83527HG chip(manual attached) which includes the watchdog functionality. When I enable the watchdog feature in UEFI, then the workstation resets with 300s interval as expected because nothing resets the watchdog from operating system. As I have no previous experience with assembler, then this seemed to be a good opportunity to learn. Based on the example in the manual on page 18 I ended up with following simple program:
$ cat -n wd_reset.a
1 ;-----------------------------------------------------
2 ; Enter the Extended Function Mode
3 ;-----------------------------------------------------
4 MOV DX, 0x2E
5 MOV AL, 0x87
6 OUT DX, AL
7 OUT DX, AL
8 ;-----------------------------------------------------------------------------
9 ; Configure Logical Device 8, Configuration Register CRF6
10 ;-----------------------------------------------------------------------------
11 MOV DX, 0x2E
12 MOV AL, 0x07
13 OUT DX, AL ; point to Logical Device Number Reg.
14 MOV DX, 0x2F
15 MOV AL, 0x08
16 OUT DX, AL ; select Logical Device 8
17 ;
18 MOV DX, 0x2E
19 MOV AL, 0xF6
20 OUT DX, AL ; select CRF6
21 MOV DX, 0x2F
22 MOV AL, 0x01
23 OUT DX, AL ; update CRF6 with value 01H
24 ;----------------------------------------------------------------------------
25 ; Exit the Extended Function Mode
26 ;----------------------------------------------------------------------------
27 MOV DX, 0x2E
28 MOV AL, 0xAA
29 OUT DX, AL
$
First two OUT instructions on lines 6 and 7 are needed to enter the Extended Function mode. On lines 14-16 I select the Logical Device 8. I do this because page 16 in the manual tells that the watch dog(WDTO) is Logical Device 8. On lines 18 - 20 I select the Configuration Register F6 and on lines 21-23 I update it with 1 because the manual says that:
The time-out value is set at Logical Device 8, CR [F6h]. Writing zero disables the Watchdog Timer function. Writing any non-zero value to this register causes the counter to load this value into the Watchdog Timer counter and start counting down.
This is from page 105. However, I'm not sure that this is the correct Configuration Register to write to in order to reset the watchdog timer..
Then I assembled this program with yasm and made the executable with ld:
$ yasm -f elf64 -o wd_reset.o wd_reset.a
$ ld -g -o wd_reset wd_reset.o
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400080
$
Now when I run this using debugger, then the program receives the SIGSEGV which should mean that it tries to access a restricted area in the memory:
$ gdb ./wd_reset
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./wd_reset...(no debugging symbols found)...done.
(gdb) run
Starting program: /home/martin/wd_reset
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400086 in ?? ()
(gdb)
I'm pretty sure that I made multiple mistakes along the way.. For example, is the Configuration Register 0xF6 the correct one to reset the watchdog? Can I assembler the program the way I did in my operating system if I want it to work with W83527HG chip?
I believe that watchdog type is already supported by the Linux kernel's watchdog framework, in the w83627hf_wdt driver.
I tried that, but this does not seem to work:
# modprobe -v w83627hf_wdt
insmod /lib/modules/4.4.0-170-generic/kernel/drivers/watchdog/w83627hf_wdt.ko
modprobe: ERROR: could not insert 'w83627hf_wdt': No such device
#
In addition, I tried with w83877f_wdt, wm8350_wdt and wm831x_wdt drivers, but none of those worked.
I haven't looked at your code, but you can't access I/O ports (or any hardware resources) directly with just normal user permissions.
Thanks for pointing this out. I tried under the root user, but the result is the same(probably because my program is faulty):
# gdb ./wd_reset
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./wd_reset...(no debugging symbols found)...done.
(gdb) run
Starting program: /home/martin/wd_reset
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400086 in ?? ()
(gdb)
I believe that watchdog type is already supported by the Linux kernel's watchdog framework, in the w83627hf_wdt driver.
I tried that, but this does not seem to work:
# modprobe -v w83627hf_wdt
insmod /lib/modules/4.4.0-170-generic/kernel/drivers/watchdog/w83627hf_wdt.ko
modprobe: ERROR: could not insert 'w83627hf_wdt': No such device
#
[/quote]
don't you need to give it some parameters like it would normally get from a devicetree?
Nominal Animal, thanks for extensive reply! However, my goal was not to build a production-quality watchdog driver, but rather try assembler language which I have no previous experience with. I even have no plans to actually start using that watchdog.
Am I correct, that in theory, if I would like to use the assembler program in my initial post, then I should build this in a way that it is a compatible Linux kernel module?
andersm, yes, I did check the kernel ring buffer after trying to insert the module and it does not print anything:
$ sudo modprobe w83627hf_wdt ; dmesg | grep -e w83627hf_wdt
modprobe: ERROR: could not insert 'w83627hf_wdt': No such device
$
langwadt, do you mean module parameters? If yes, then I don't think so. However, I tried with "modprobe -v w83627hf_wdt timeout=100 nowayout=0 early_disable=0" and this didn't change anything.
Nominal Animal, thanks for extensive reply! However, my goal was not to build a production-quality watchdog driver, but rather try assembler language which I have no previous experience with. I even have no plans to actually start using that watchdog.
Am I correct, that in theory, if I would like to use the assembler program in my initial post, then I should build this in a way that it is a compatible Linux kernel module?
andersm, yes, I did check the kernel ring buffer after trying to insert the module and it does not print anything:
$ sudo modprobe w83627hf_wdt ; dmesg | grep -e w83627hf_wdt
modprobe: ERROR: could not insert 'w83627hf_wdt': No such device
$
langwadt, do you mean module parameters? If yes, then I don't think so. However, I tried with "modprobe -v w83627hf_wdt timeout=100 nowayout=0 early_disable=0" and this didn't change anything.
without parameters how does the driver know which bus/address/etc. to use ?
Am I correct, that in theory, if I would like to use the assembler program in my initial post, then I should build this in a way that it is a compatible Linux kernel module?
Either as a kernel module, or use the available kernel interfaces (like ioperm() (http://man7.org/linux/man-pages/man2/ioperm.2.html)) to gain access to specific I/O ports, yes.
If you wish to write a pure assembly program, the _start label tells the linker where execution should start when the binary is loaded. When you use e.g. a C compiler, it inserts its own startup code there, which calls main() using the platform-specific C ABI. On x86-64 (64-bit Intel and AMD processors), Linux uses SYSV ABI. I've written a full freestanding C example here (https://stackoverflow.com/questions/39927790/c-standard-library-functions-vs-system-calls-which-is-open/39932430#39932430), which includes the generated assembly code in the ELF binary (in AT&T assembly format; the main difference to Intel syntax being the operand order -- target, source instead of Intel syntax source, target).
$ sudo modprobe w83627hf_wdt ; dmesg | grep -e w83627hf_wdt
modprobe: ERROR: could not insert 'w83627hf_wdt': No such device
$
OK, so it looks like w83627hf_wdt does not actually support your chip. It uses I/O ports 0x2e and 0x4e to detect the chip (and these are hardcoded, not devicetree-controlled), and fails to detect your chip.
The driver uses the same approach as in your example (writes 0x87 to port 0x2e, in superio_enter()) to enable the extended registers, and to use logical device 8 (the superio_select(W83627HF_LD_WDT) call in wdt_find()). However, because in your case neither pr_err() or pr_info() gets executed, the driver code must fail the wdt_find() call in wdt_init() (the latter being the function called when the driver is loaded).
I forgot to mention that the easiest way to trace the function call chain and macro values is probably via Bootlin Elixir (https://elixir.bootlin.com/linux/v4.4.170/source/drivers/watchdog/w83627hf_wdt.c#L420), starting with kernel 4.4.170 sources, and the drivers/watchdog/w83627hf_wdt.c:wdt_init() function, because on that site each function, variable, or macro name is a clickable link. Just remember to always select the w83627hf_wdt.c file, if the same name occurs in multiple files.
without parameters how does the driver know which bus/address/etc. to use ?
It's hardcoded in the driver, in the wdt_init() and wdt_find() functions. It is possible to expose the base port number (it is a variable, static int wdt_io), but there does not seem to have been any need to thus far.
As far as I can see, the driver implements the same operations as the example assembly code, but does not behave as the manual describes. (It does use the workaround of writing 0x87 to port 0x2e twice, too.)
So, I don't really know where the problem lies. It would help knowing what the motherboard is.
Motherboard is a Supermicro X9DR3-F (https://www.supermicro.com/manuals/motherboard/C606_602/MNL-1259.pdf).
In a meanwhile, I added some debug code to superio_outb(), superio_inb(), superio_enter() and wdt_find() functions. When I try to load the module, then following is printed to kernel ring buffer:
[Mon Jan 6 22:37:34 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 6 22:37:34 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 6 22:37:34 2020] DEBUG: superio_enter() returned: 0x0
[Mon Jan 6 22:37:34 2020] DEBUG: superio_outb(): write 0x7 to 0x2e
[Mon Jan 6 22:37:34 2020] DEBUG: superio_outb(): write 0x8 to 0x2f
[Mon Jan 6 22:37:34 2020] DEBUG: superio_inb(): write 0x20 to 0x2e
[Mon Jan 6 22:37:34 2020] DEBUG: superio_inb(): read 0x2f
[Mon Jan 6 22:37:34 2020] DEBUG: superio_inb() returned: 0xff
[Mon Jan 6 22:37:34 2020] DEBUG: superio_enter(): write 0x87 to 0x4e
[Mon Jan 6 22:37:34 2020] DEBUG: superio_enter(): write 0x87 to 0x4e
[Mon Jan 6 22:37:34 2020] DEBUG: superio_enter() returned: 0x0
[Mon Jan 6 22:37:34 2020] DEBUG: superio_outb(): write 0x7 to 0x4e
[Mon Jan 6 22:37:34 2020] DEBUG: superio_outb(): write 0x8 to 0x4f
[Mon Jan 6 22:37:34 2020] DEBUG: superio_inb(): write 0x20 to 0x4e
[Mon Jan 6 22:37:34 2020] DEBUG: superio_inb(): read 0x4f
[Mon Jan 6 22:37:34 2020] DEBUG: superio_inb() returned: 0xff
[Mon Jan 6 22:37:34 2020] Detection failed!
I guess the "write 0x20 to 0x2e" step("val = superio_inb(0x20);" line) and then "read 0x2f" should detect the watchdog chip model/ID? In my case it returns 0xff..
The motherboard manual says (on page 1-9) that the W83527 SuperIO chip is connected to the Nuvoton WPCM405R baseboard management controller, which provides IPMI and other stuff; it is an intelligent controller.
It looks like either the SuperIO chip is exposed at a different port, or the WPCM405R is blocking the access to the watchdog on the W83527 chip. The way the motherboard has a jumper to select between system reboot and an NMI signal makes me suspect the W83527 chip is not directly accessible, or at least not like on boards without a baseboard management controller or described in the W83527 manual.
Hmm..indeed.
Could you install the lm-sensors package, and run /usr/sbin/sensors-detect (as root), scanning at least the Super I/O and ISA I/O ports, to see if it can find the W83527 hardware sensors (it has some temperature and fan speed sensors)? If the W83527 is accessible at a nonstandard I/O port, lm-sensors should detect it; and if it does, it'll tell where it found it in the final output configuration.
Output of "/usr/sbin/sensors-detect --auto" executed in root permissions is attached.
When I look the source code of sensors-detect, then looks like it uses w83627ehf (https://github.com/torvalds/linux/blob/master/drivers/hwmon/w83627ehf.c) driver for W83527HG chip. I'm able to insert this module if I specify the chip ID manually:
$ sudo modprobe -v w83627ehf force_id=0xb070
insmod /lib/modules/4.4.0-170-generic/kernel/drivers/hwmon/hwmon-vid.ko
insmod /lib/modules/4.4.0-170-generic/kernel/drivers/hwmon/w83627ehf.ko force_id=0xb070
$ sudo dmesg -T | tail -1
[Tue Jan 7 14:23:28 2020] w83627ehf: Found W83627DHG-P chip at 0xfff8
$
Maybe I could modify the w83627hf_wdt (https://github.com/torvalds/linux/blob/master/drivers/watchdog/w83627hf_wdt.c) module in a way that the watchdog chip model/ID detection step is skipped? However, I highly doubt that it actually helps, i.e maybe it allows one to load the driver, but I doubt that it is able to communicate with watchdog chip once loaded.
[Tue Jan 7 14:23:28 2020] w83627ehf: Found W83627DHG-P chip at 0xfff8
Okay, so the w83627ehf driver does find the chip (in drivers/hwmon/w83627ehf.c:sensors_w83627ehf_init() (https://elixir.bootlin.com/linux/v4.4.170/source/drivers/hwmon/w83627ehf.c#L2800)) via port 0x2e or 0x4e, using drivers/hwmon/w83627ehf.c:w83627ehf_find() (https://elixir.bootlin.com/linux/v4.4.170/source/drivers/hwmon/w83627ehf.c#L2700). Do note that it does not check the chip like the watchdog driver does.
Comparing drivers/hwmon/w83627ehf.c:superio_enter() (https://elixir.bootlin.com/linux/v4.4.170/source/drivers/hwmon/w83627ehf.c#L139) and drivers/watchdog/w83627hf.c:superio_enter() (https://elixir.bootlin.com/linux/v4.4.170/source/drivers/watchdog/w83627hf_wdt.c#L119), we see they do the exact same thing wrt. I/O port accesses: writes 0x87 to port 0x2e (to 0x4e on the second try), twice.
Comparing drivers/hwmon/w83627ehf.c:superio_select() (https://elixir.bootlin.com/linux/v4.4.170/source/drivers/hwmon/w83627ehf.c) and drivers/watchdog/w83627hf_wdt.c:superio_select() (https://elixir.bootlin.com/linux/v4.4.170/source/drivers/watchdog/w83627hf_wdt.c#L130) we see they also do the same thing wrt. I/O port accesses: write 7 to the I/O port 0x2e/0x4e, then the selected logical device to the next higher I/O port. In the watchdog driver, the only call used is superio_select(W83627HF_LD_WDT) , i.e. superio_select(8), to select the logical device 8. The hwmon driver (for W83627DHG_P) only uses superio_select(W83627EHF_LD_HWM) , i.e. superio_select(0xB).
So, there does not seem to be any bug or issue as to how the W83527HG is accessed, as sensors-detect finds it just fine using ports 0x2e,0x2f or 0x4e,0x4f. That code does not check the chip ID like the watchdog driver does, though.
Could you add a pr_err("WDT: Detected ID 0x%x.\n", val); to drivers/watchdog/w83627hf_wdt.c:wdt_find() (https://elixir.bootlin.com/linux/v4.4.170/source/drivers/watchdog/w83627hf_wdt.c#L336), just after the val=superio_inb(0x20); line?
If I read your added print output right, that should yield "WDT: Detected ID 0xff" in dmesg; for W83527HG, you really should get "WDT: Detected ID 0xb0".
You can also override the detection by adding val=W83627DHG_P_ID; before the switch (val) there. It is the minimum code modification that simply overrides the model/id detection.
[Tue Jan 7 14:23:28 2020] w83627ehf: Found W83627DHG-P chip at 0xfff8
Okay, so the w83627ehf driver does find the chip (in drivers/hwmon/w83627ehf.c:sensors_w83627ehf_init() (https://elixir.bootlin.com/linux/v4.4.170/source/drivers/hwmon/w83627ehf.c#L2800)) via port 0x2e or 0x4e, using drivers/hwmon/w83627ehf.c:w83627ehf_find() (https://elixir.bootlin.com/linux/v4.4.170/source/drivers/hwmon/w83627ehf.c#L2700). Do note that it does not check the chip like the watchdog driver does.
Do you know this because pointer addr value is not 0, i.e (*addr == 0) condition is not satisfied and thus ENODEV is not returned?
Comparing drivers/hwmon/w83627ehf.c:superio_select() (https://elixir.bootlin.com/linux/v4.4.170/source/drivers/hwmon/w83627ehf.c) and drivers/watchdog/w83627hf_wdt.c:superio_select() (https://elixir.bootlin.com/linux/v4.4.170/source/drivers/watchdog/w83627hf_wdt.c#L130) we see they also do the same thing wrt. I/O port accesses: write 7 to the I/O port 0x2e/0x4e, then the selected logical device to the next higher I/O port. In the watchdog driver, the only call used is superio_select(W83627HF_LD_WDT) , i.e. superio_select(8), to select the logical device 8. The hwmon driver (for W83627DHG_P) only uses superio_select(W83627EHF_LD_HWM) , i.e. superio_select(0xB).
I understood this part exactly as you did. In case of w83627hf_wdt.c it's clear that 0x7 is written to 0x2e and then 0x8(logical device number for watchdog) is written to 0x2f. In case of w83627ehf.c it writes 0x07 to 0x2e and then 0x0b(logical device number for hardware monitor) to 0x2f.
Could you add a pr_err("WDT: Detected ID 0x%x.\n", val); to drivers/watchdog/w83627hf_wdt.c:wdt_find() (https://elixir.bootlin.com/linux/v4.4.170/source/drivers/watchdog/w83627hf_wdt.c#L336), just after the val=superio_inb(0x20); line?
If I read your added print output right, that should yield "WDT: Detected ID 0xff" in dmesg; for W83527HG, you really should get "WDT: Detected ID 0xb0".
Yes, superio_inb() returns 0xff:
[Thu Jan 9 13:29:58 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Thu Jan 9 13:29:58 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Thu Jan 9 13:29:58 2020] DEBUG: superio_enter() returned: 0x0
[Thu Jan 9 13:29:58 2020] DEBUG: superio_outb(): write 0x7 to 0x2e
[Thu Jan 9 13:29:58 2020] DEBUG: superio_outb(): write 0x8 to 0x2f
[Thu Jan 9 13:29:58 2020] DEBUG: superio_inb(): write 0x20 to 0x2e
[Thu Jan 9 13:29:58 2020] DEBUG: superio_inb(): read 0x2f
[Thu Jan 9 13:29:58 2020] w83627hf_wdt: WDT: Detected ID 0xff.
[Thu Jan 9 13:29:58 2020] DEBUG: superio_enter(): write 0x87 to 0x4e
[Thu Jan 9 13:29:58 2020] DEBUG: superio_enter(): write 0x87 to 0x4e
[Thu Jan 9 13:29:58 2020] DEBUG: superio_enter() returned: 0x0
[Thu Jan 9 13:29:58 2020] DEBUG: superio_outb(): write 0x7 to 0x4e
[Thu Jan 9 13:29:58 2020] DEBUG: superio_outb(): write 0x8 to 0x4f
[Thu Jan 9 13:29:58 2020] DEBUG: superio_inb(): write 0x20 to 0x4e
[Thu Jan 9 13:29:58 2020] DEBUG: superio_inb(): read 0x4f
[Thu Jan 9 13:29:58 2020] w83627hf_wdt: WDT: Detected ID 0xff.
[Thu Jan 9 13:29:58 2020] Detection failed!
You can also override the detection by adding val=W83627DHG_P_ID; before the switch (val) there. It is the minimum code modification that simply overrides the model/id detection.
I tried this before with W83627HF_ID, but this didn't work. The system still rebooted if watchdog feature in UEFI was enabled. I'll try with W83627DHG_P_ID.
[Tue Jan 7 14:23:28 2020] w83627ehf: Found W83627DHG-P chip at 0xfff8
Okay, so the w83627ehf driver does find the chip (in drivers/hwmon/w83627ehf.c:sensors_w83627ehf_init() (https://elixir.bootlin.com/linux/v4.4.170/source/drivers/hwmon/w83627ehf.c#L2800)) via port 0x2e or 0x4e, using drivers/hwmon/w83627ehf.c:w83627ehf_find() (https://elixir.bootlin.com/linux/v4.4.170/source/drivers/hwmon/w83627ehf.c#L2700). Do note that it does not check the chip like the watchdog driver does.
Do you know this because pointer addr value is not 0, i.e (*addr == 0) condition is not satisfied and thus ENODEV is not returned?
Wait; I goofed. Your sensors-detect output shows that it does NOT find any Nuvoton Super-I/O chips at all.
I somehow assumed that because the w83627ehf module, when loaded, finds the ISA area at 0xfff8, that lm-sensors found it.
That is not correct. If there is no Super-I/O chip at all at ports 0x2e..0x2f or 0x4e..0x4f, forcing the chip id will yield ISA area address 0xfff8, as the "probing" reads 0xff 0xff for the address from unused ports, and the address mask is ~7: 0xffff & (~7) = 0xfff8.
In other words, there is no Super-I/O chip accessible at that port on your machine. (It is common for "standard" I/O ports to read as 0xFF, if they are unused.)
There could be a BIOS/EFI setting to enable it, or indeed the Super-IO chip could be wired to the system management controller (which is more or less like a small subsidiary computer also on the motherboard), and not directly accessible by either main Intel processor.
Yes, superio_inb() returns 0xff:
[Thu Jan 9 13:29:58 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Thu Jan 9 13:29:58 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Thu Jan 9 13:29:58 2020] DEBUG: superio_enter() returned: 0x0
[Thu Jan 9 13:29:58 2020] DEBUG: superio_outb(): write 0x7 to 0x2e
[Thu Jan 9 13:29:58 2020] DEBUG: superio_outb(): write 0x8 to 0x2f
[Thu Jan 9 13:29:58 2020] DEBUG: superio_inb(): write 0x20 to 0x2e
[Thu Jan 9 13:29:58 2020] DEBUG: superio_inb(): read 0x2f
[Thu Jan 9 13:29:58 2020] w83627hf_wdt: WDT: Detected ID 0xff.
[Thu Jan 9 13:29:58 2020] DEBUG: superio_enter(): write 0x87 to 0x4e
[Thu Jan 9 13:29:58 2020] DEBUG: superio_enter(): write 0x87 to 0x4e
[Thu Jan 9 13:29:58 2020] DEBUG: superio_enter() returned: 0x0
[Thu Jan 9 13:29:58 2020] DEBUG: superio_outb(): write 0x7 to 0x4e
[Thu Jan 9 13:29:58 2020] DEBUG: superio_outb(): write 0x8 to 0x4f
[Thu Jan 9 13:29:58 2020] DEBUG: superio_inb(): write 0x20 to 0x4e
[Thu Jan 9 13:29:58 2020] DEBUG: superio_inb(): read 0x4f
[Thu Jan 9 13:29:58 2020] w83627hf_wdt: WDT: Detected ID 0xff.
[Thu Jan 9 13:29:58 2020] Detection failed!
Okay; this supports that there is nothing responding to writes to and reads from I/O ports 0x2e..0x2f, 0x4e..0x4f at all.
That is, there is no W83527HG super-I/O chip even the kernel can directly access.
I tried this before with W83627HF_ID, but this didn't work. The system still rebooted if watchdog feature in UEFI was enabled. I'll try with W83627DHG_P_ID.
It won't make a difference, I'm afraid.
I am convinced now that the W83527HG chip that is on your motherboard, is connected to the system management controller, and not directly accessible by the main CPUs. We'd need system management controller programming information from Supermicro, and run our code on that, to be able to connect to the chip, but that kind of info is deep secret sauce they'll never divulge.
If this was only to learn to write assembler code, it was a very unfortunate start... I would instead recommend looking at writing your own simple freestanding applications, using the x86-64/AMD64 Linux Kernel ABI directly. If you want, I could start a new programming thread, with a working example, and pointers to relevant information (like where to find how to do syscalls, and find which syscalls are available).
However, in practice, I personally mostly use GCC extended inline assembly in C programs (also works in Arduino environment, because it also uses GCC). I even tend to use built-in intrinsics and <mmintrin.h> for vectorized (SSE/AVX) calculations, though.
I do very warmly recommend Atmega32u4-based microcontrollers for such learning purposes also, because it has a native USB interface (no programming dongles, can become any kind of max. 12 MBit/s USB device), and can be programmed either in the Arduino environment, or on bare metal using avr-gcc and avr-libc only; avr-gcc also includes an assembler, so you can even write your microcontroller firmware from scratch using assembly only.
Although I like Teensy 2.0 the best (of ATmega32u4-based microcontrollers), I've been happily using the 3€-5€ Pro Micro clones off eBay. (One just needs to remember to treat them as Arduino Leonardos in the Arduino environment, because they come with the Leonardo bootloader. Leonardo itself also uses ATmega32u4, but has the bigger Arduino form-factor.)
I tried this before with W83627HF_ID, but this didn't work. The system still rebooted if watchdog feature in UEFI was enabled. I'll try with W83627DHG_P_ID.
It won't make a difference, I'm afraid.
Yes, as expected, it didn't help. Driver tries to write to 0x2e and 0x2f addresses with 5 second interval in order to reset the watchdog:
[Mon Jan 13 12:01:43 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0x7 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0x8 to 0x2f
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0xf6 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0x3c to 0x2f
[Mon Jan 13 12:01:43 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0x7 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0x8 to 0x2f
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0xf6 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0x3c to 0x2f
[Mon Jan 13 12:01:43 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0x7 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0x8 to 0x2f
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0xf6 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0x3c to 0x2f
[Mon Jan 13 12:01:43 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0x7 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0x8 to 0x2f
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0xf6 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0x3c to 0x2f
[Mon Jan 13 12:01:43 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0x7 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0x8 to 0x2f
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0xf6 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0x3c to 0x2f
[Mon Jan 13 12:01:43 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0x7 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0x8 to 0x2f
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0xf6 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0x3c to 0x2f
[Mon Jan 13 12:01:43 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0x7 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0x8 to 0x2f
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0xf6 to 0x2e
[Mon Jan 13 12:01:43 2020] DEBUG: superio_outb(): write 0x3c to 0x2f
[Mon Jan 13 12:01:48 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0x7 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0x8 to 0x2f
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0xf6 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0x3c to 0x2f
[Mon Jan 13 12:01:48 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0x7 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0x8 to 0x2f
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0xf6 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0x3c to 0x2f
[Mon Jan 13 12:01:48 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0x7 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0x8 to 0x2f
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0xf6 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0x3c to 0x2f
[Mon Jan 13 12:01:48 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0x7 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0x8 to 0x2f
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0xf6 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0x3c to 0x2f
[Mon Jan 13 12:01:48 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0x7 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0x8 to 0x2f
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0xf6 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0x3c to 0x2f
[Mon Jan 13 12:01:48 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0x7 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0x8 to 0x2f
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0xf6 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0x3c to 0x2f
[Mon Jan 13 12:01:48 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_enter(): write 0x87 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0x7 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0x8 to 0x2f
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0xf6 to 0x2e
[Mon Jan 13 12:01:48 2020] DEBUG: superio_outb(): write 0x3c to 0x2f
..but the server still reboots. However, thanks for all the information and help!
There is no point in a watchdog which can't be accessed by software :P
Maybe it's some other watchdog than the SuperIO? For example, some Intel southbridges have WDTs and there is a different driver for those.
Do you have Windows drivers/utilities for it?
The UEFI option seems to control the Super I/O watchdog. The PCH(Intel C606 in my case) indeed has a watchdog, but this works as expected with iTCO-wdt (https://github.com/torvalds/linux/blob/master/drivers/watchdog/iTCO_wdt.c) module.
I have no Windows drivers/utilities for the Super I/O watchdog.