Author Topic: assembler program to reset Nuvoton W83527HG watchdog  (Read 721 times)

0 Members and 1 Guest are viewing this topic.

Offline m4rtin

  • Regular Contributor
  • *
  • Posts: 91
assembler program to reset Nuvoton W83527HG watchdog
« on: January 03, 2020, 09:46:31 pm »
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:

Code: [Select]
$ 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:

Quote
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:
Code: [Select]
$ 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:
Code: [Select]
$ 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?
« Last Edit: January 03, 2020, 09:54:02 pm by m4rtin »
 

Offline andersm

  • Super Contributor
  • ***
  • Posts: 1119
  • Country: fi
Re: assembler program to reset Nuvoton W83527HG watchdog
« Reply #1 on: January 03, 2020, 10:50:51 pm »
I believe that watchdog type is already supported by the Linux kernel's watchdog framework, in the w83627hf_wdt driver. 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.

Offline m4rtin

  • Regular Contributor
  • *
  • Posts: 91
Re: assembler program to reset Nuvoton W83527HG watchdog
« Reply #2 on: January 03, 2020, 11:20:19 pm »
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:
Code: [Select]
# 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.

Quote from: andersm
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):
Code: [Select]
# 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)
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 1490
  • Country: fi
    • My home page and email address
Re: assembler program to reset Nuvoton W83527HG watchdog
« Reply #3 on: January 04, 2020, 01:25:20 am »
Based on the example in the manual on page 18 I ended up with following simple program:
No.  Linux, and other operating systems like Windows and MacOS, do not allow arbitrary programs direct access to chips and devices.

In Linux, you need to use a watchdog kernel driver.  In your case, w83627hf_wdt should support yours, but for some reason, does not detect your W83527HG chip correctly.  (According to hwmon developers, W83527HG is a variant of W83627DHG-P with just fewer features but "hopefully compatible".)

Even if you were to create an userspace application (it is possible), it would not work as well as the kernel driver.  In particular, it would either consume a lot of unnecessary CPU time, OR cause the machine to reboot at very heavy loads.  No, you do not want to go that route.



Looking at the datasheet, it says the Chip ID is C1 on page 72 (chapter 9.40).  If we look at the w83627hf_wdt driver, we find it does not detect it.  It would have w83527hg in the enum chips on line 51 or so, and "W83527HG" in the corresponding position in the chip_name array in wdt_init on line 471-493;
    #define W83527HG_ID 0xc1
between lines 94 and 95; a
    case w83527hg:
somewhere in w83627hf_init() around line 167-216; and
    case W83527HG_ID:
        ret = w83527hg;
        break;
in wdt_find() around line 349-427.

I didn't bother checking if the W83527HG needs specific handling; there might be a few additional lines, if the manual says it needs different handling compared to one of the existing chips the driver already supports.

You could contact the driver author (Pádraig Brady, address listed at the bottom of the source file, linked to above), include the manual PDF or a link to this discussion, and ask if they would help with the patch.  You'd need to learn how to recompile your Linux kernel in Ubuntu, applying the patch needed to the w83627hf_wdt.c driver.  You'd need to test the driver, and report any issues or success to the author, but if successful, it would be included in the vanilla Linux; you could then ask Greg KH to include the patch in the stable kernel series (Brady might do that automatically), and even the Ubuntu folks to include it in standard Ubuntu kernels if they don't pick it up automatically, getting the support into all future Ubuntu kernels.  It will be months before the changes percolate down to the kernels you use, so in the mean time, you'd need to recompile your own kernels.  Overall, it is still the path of least work, and although it does require some effort from you, this is the path I would take myself -- and I'm very lazy myself.

You should definitely mention which motherboard this is, as well.  It does not matter if there are just a few in use; these kind of additional support details are almost always happily added by the developers like Brady.  Just make sure you are willing to do the testing and checking they ask, first.
 

Offline andersm

  • Super Contributor
  • ***
  • Posts: 1119
  • Country: fi
Re: assembler program to reset Nuvoton W83527HG watchdog
« Reply #4 on: January 04, 2020, 01:44:59 am »
Looking at the datasheet, it says the Chip ID is C1 on page 72 (chapter 9.40).
If I read the driver correctly, it reads the chip ID from global register 0x20, which should return 0xB0, the same ID used for the W83627DHG-P.

Edit: m4rtin, have you checked if the driver printed anything in the kernel logs?
« Last Edit: January 04, 2020, 01:51:17 am by andersm »
 

Online langwadt

  • Super Contributor
  • ***
  • Posts: 1723
  • Country: dk
Re: assembler program to reset Nuvoton W83527HG watchdog
« Reply #5 on: January 04, 2020, 02:23:29 am »
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:
Code: [Select]
# 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?
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 1490
  • Country: fi
    • My home page and email address
Re: assembler program to reset Nuvoton W83527HG watchdog
« Reply #6 on: January 04, 2020, 02:58:40 am »
Looking at the datasheet, it says the Chip ID is C1 on page 72 (chapter 9.40).
If I read the driver correctly, it reads the chip ID from global register 0x20, which should return 0xB0, the same ID used for the W83627DHG-P.
Good catch, indeed it does.  I was too quick-and-lazy with my reading...  and the current maintainer is Guenter Roeck, too.

The output of
    sudo modprobe w83627hf_wdt ; dmesg | grep -e w83627hf_wdt
would be a good place to start.
 

Offline m4rtin

  • Regular Contributor
  • *
  • Posts: 91
Re: assembler program to reset Nuvoton W83527HG watchdog
« Reply #7 on: January 05, 2020, 12:21:13 am »
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:
Code: [Select]
$ 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.
 

Online langwadt

  • Super Contributor
  • ***
  • Posts: 1723
  • Country: dk
Re: assembler program to reset Nuvoton W83527HG watchdog
« Reply #8 on: January 05, 2020, 12:46:01 am »
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:
Code: [Select]
$ 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 ?






 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 1490
  • Country: fi
    • My home page and email address
Re: assembler program to reset Nuvoton W83527HG watchdog
« Reply #9 on: January 05, 2020, 06:17:31 am »
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()) 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, 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).

Code: [Select]
$ 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, 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.
« Last Edit: January 05, 2020, 06:19:07 am by Nominal Animal »
 

Offline m4rtin

  • Regular Contributor
  • *
  • Posts: 91
Re: assembler program to reset Nuvoton W83527HG watchdog
« Reply #10 on: January 06, 2020, 08:51:22 pm »
Motherboard is a Supermicro X9DR3-F.
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:
Code: [Select]
[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..
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 1490
  • Country: fi
    • My home page and email address
Re: assembler program to reset Nuvoton W83527HG watchdog
« Reply #11 on: January 07, 2020, 06:23:27 am »
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.

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.

Personally, I suspect you simply picked a motherboard and SuperIO chip combination that does not expose the SuperIO chip normally (or at all)... but hopefully I'm wrong as usual :D
 

Offline m4rtin

  • Regular Contributor
  • *
  • Posts: 91
Re: assembler program to reset Nuvoton W83527HG watchdog
« Reply #12 on: January 07, 2020, 12:34:19 pm »
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 driver for W83527HG chip. I'm able to insert this module if I specify the chip ID manually:
Code: [Select]
$ 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 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.
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 1490
  • Country: fi
    • My home page and email address
Re: assembler program to reset Nuvoton W83527HG watchdog
« Reply #13 on: January 08, 2020, 07:01:05 am »
Code: [Select]
[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()) via port 0x2e or 0x4e, using drivers/hwmon/w83627ehf.c:w83627ehf_find().  Do note that it does not check the chip like the watchdog driver does.

Comparing drivers/hwmon/w83627ehf.c:superio_enter() and drivers/watchdog/w83627hf.c:superio_enter(), 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() and drivers/watchdog/w83627hf_wdt.c:superio_select() 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(), 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.
 

Offline m4rtin

  • Regular Contributor
  • *
  • Posts: 91
Re: assembler program to reset Nuvoton W83527HG watchdog
« Reply #14 on: January 09, 2020, 11:47:50 am »
Code: [Select]
[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()) via port 0x2e or 0x4e, using drivers/hwmon/w83627ehf.c:w83627ehf_find().  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() and drivers/watchdog/w83627hf_wdt.c:superio_select() 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(), 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:
Code: [Select]
[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.
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 1490
  • Country: fi
    • My home page and email address
Re: assembler program to reset Nuvoton W83527HG watchdog
« Reply #15 on: January 09, 2020, 02:15:16 pm »
Code: [Select]
[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()) via port 0x2e or 0x4e, using drivers/hwmon/w83627ehf.c:w83627ehf_find().  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:
Code: [Select]
[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.)
« Last Edit: January 09, 2020, 02:16:50 pm by Nominal Animal »
 

Offline magic

  • Super Contributor
  • ***
  • Posts: 1795
  • Country: pl
Re: assembler program to reset Nuvoton W83527HG watchdog
« Reply #16 on: January 12, 2020, 03:29:57 pm »
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?
 

Offline m4rtin

  • Regular Contributor
  • *
  • Posts: 91
Re: assembler program to reset Nuvoton W83527HG watchdog
« Reply #17 on: January 13, 2020, 10:18:14 am »
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:
Code: [Select]
[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 module.

I have no Windows drivers/utilities for the Super I/O watchdog.
 

Offline magic

  • Super Contributor
  • ***
  • Posts: 1795
  • Country: pl
Re: assembler program to reset Nuvoton W83527HG watchdog
« Reply #18 on: January 13, 2020, 11:19:30 am »
I'm kinda surprised that the SuperIO doesn't respond. Watchdog by far isn't its only purpose, it ought to be connected to the system LPC ISA bus for things like the keyboard controller or serial ports to work.

Are you sure you identified the chip correctly? Do you have the datasheet?
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 1490
  • Country: fi
    • My home page and email address
Re: assembler program to reset Nuvoton W83527HG watchdog
« Reply #19 on: January 13, 2020, 12:01:07 pm »
Do you have the datasheet?
As linked to above, it's a Supermicro X9DR3-F motherboard.  In a diagram, it shows the W83527 SuperIO chip connected to the PCH C606.  The Nuvoton W83527 PDF was also linked to from above.
 

Offline magic

  • Super Contributor
  • ***
  • Posts: 1795
  • Country: pl
Re: assembler program to reset Nuvoton W83527HG watchdog
« Reply #20 on: January 13, 2020, 03:26:18 pm »
On second thought, you may be right that it's hidden behind the BMC chip to support things like console redirection. I have no familiarity with IPMI motherboard internals.

But there has to be some way or they wouldn't be including those jumpers and everything :-//

What's the output of lspci, by the way? Any ISA bridges?
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 1490
  • Country: fi
    • My home page and email address
Re: assembler program to reset Nuvoton W83527HG watchdog
« Reply #21 on: January 13, 2020, 03:55:27 pm »
Because of the KVM over LAN support (it even has a dedicated LAN port for the WPCM450/IPMI etc., and the KVM works even in BIOS), it makes sense for the SuperIO chip to be connected to the WPCM450 system management controller.

Since the Intel PCH C606 (used on that motherboard) does include the Intel Management Engine, I think direct access to the SuperIO chip is disabled by the C606.  There probably is some way to enable that access, perhaps via IPMI or some kind of Supermicro secret voodoo, but at this point, I wouldn't bother.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf