2019-04-01 10:25:59

by Matteo Croce

[permalink] [raw]
Subject: [PATCH 0/4] Introduce the aural error reporting framework

The Linux kernel has had verbal error reporting since the beginning.
Different error conditions trigger different error messages, with
different severity: from a simple warning to the most feared kernel panic.

While this detailed error reporting is much helpful to developers or end
users, there are some cases in which it's impossible to notice that an
error happened.
The most common case is headless devices, such as home servers without an
attached display, or routers without an exposed serial port. Needless
to say, logging into the machine via SSH is not an option after such
a severe error.
In other cases the monitor might be attached, but the system is unable to
display the error, probably because there is an X server running and
the KMS switch fails. Or simply the user is visually impaired.

These are all cases when the aural errors framework comes to help. This
framework adds to the kernel a generic library to play sounds, which can
be used to report errors or generic events.

As the sound card driver could, and most probably will, become unusable
during a kernel crash, the sounds are played via the system buzzer which
has been around since the dawn of time.
The buzzer driver is simple, requires just a few register writes to work,
the hardware is extremely cheap and is already present on most machines.

The first patch introduces the framework functions, the other three make
use of it in, respectively, kernel panic, warning and oops.
The last patch, not to be merged, creates a procfs handler useful to test
the error reporting.

Matteo Croce (4):
aural error reporting framework
panic: use the aural error reporting framework to report panics
bug: use the aural error reporting framework to report warnings
oops: use the aural error reporting framework to report oopses

arch/x86/lib/Makefile | 1 +
arch/x86/lib/play.c | 75 +++++++++++++++++++++++++++++++++++++++++++
include/linux/play.h | 34 ++++++++++++++++++++
kernel/panic.c | 61 +++++++++++++++++++++++++++++++++++
lib/Kconfig.debug | 35 ++++++++++++++++++++
5 files changed, 206 insertions(+)
create mode 100644 arch/x86/lib/play.c
create mode 100644 include/linux/play.h

--
2.20.1


2019-04-01 10:26:22

by Matteo Croce

[permalink] [raw]
Subject: [PATCH 1/4] aural error reporting framework

The Linux kernel has had verbal error reporting since the beginning.
Different error conditions trigger different error messages, with
different severity: from a simple warning to the most feared kernel panic.

While this detailed error reporting is much helpful to developers or end
users, there are some cases in which it's impossible to notice that an
error happened.
The most common case is headless devices, such as home servers without an
attached display, or routers without an exposed serial port. Needless
to say, logging into the machine via SSH is not an option after such
a severe error.
In other cases the monitor might be attached, but the system is unable to
display the error, probably because there is an X server running and
the KMS switch fails. Or simply the user is visually impaired.

These are all cases when the aural errors framework comes to help. This
framework adds to the kernel a generic library to play sounds, which can
be used to report errors or generic events.

As the sound card driver could, and most probably will, become unusable
during a kernel crash, the sounds are played via the system buzzer which
has been around since the dawn of time.
The buzzer driver is simple, requires just a few register writes to work,
the hardware is extremely cheap and is already present on most machines.

Signed-off-by: Matteo Croce <[email protected]>
---
arch/x86/lib/Makefile | 1 +
arch/x86/lib/play.c | 75 +++++++++++++++++++++++++++++++++++++++++++
include/linux/play.h | 34 ++++++++++++++++++++
lib/Kconfig.debug | 5 +++
4 files changed, 115 insertions(+)
create mode 100644 arch/x86/lib/play.c
create mode 100644 include/linux/play.h

diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index 140e61843a07..fcd1ee6adfad 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -28,6 +28,7 @@ lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o insn-eval.o
lib-$(CONFIG_RANDOMIZE_BASE) += kaslr.o
lib-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
lib-$(CONFIG_RETPOLINE) += retpoline.o
+lib-$(CONFIG_PLAY_LIB) += play.o

obj-y += msr.o msr-reg.o msr-reg-export.o hweight.o
obj-y += iomem.o
diff --git a/arch/x86/lib/play.c b/arch/x86/lib/play.c
new file mode 100644
index 000000000000..e798eeb144f8
--- /dev/null
+++ b/arch/x86/lib/play.c
@@ -0,0 +1,75 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Aural kernel panic - x86 implementation
+ *
+ * Copyright (C) 2019 Matteo Croce <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/timex.h>
+#include <linux/i8253.h>
+#include <linux/play.h>
+#include <asm/io.h>
+
+#define CONTROL_WORD_REG 0x43
+#define COUNTER2 0x42
+#define SPEAKER_PORT 0x61
+
+void arch_play_one(unsigned int ms, unsigned int hz)
+{
+ unsigned long flags;
+ u8 p61;
+
+ /* filter out non audible by humans freqs */
+ if (hz >= 16 && hz <= 22000) {
+ unsigned int count = PIT_TICK_RATE / hz;
+
+ raw_spin_lock_irqsave(&i8253_lock, flags);
+
+ /* set buzzer
+ * 0xB6
+ * 1 0 Counter 2
+ * 1 1 2xRD/2xWR bits 0..7, 8..15 of counter value
+ * 0 1 1 Mode 3: Square Wave
+ * 0 Counter is a 16 bit binary counter
+ */
+ outb_p(0xB6, CONTROL_WORD_REG);
+
+ /* select desired HZ with two writes in counter 2, port 42h */
+ outb_p(count, COUNTER2);
+ outb_p(count >> 8, COUNTER2);
+
+ /* start beep
+ * set bit 0-1 (0: SPEAKER DATA; 1: OUT2) of GATE2 (port 61h)
+ */
+ p61 = inb_p(SPEAKER_PORT);
+ if ((p61 & 3) != 3)
+ outb_p(p61 | 3, SPEAKER_PORT);
+
+ raw_spin_unlock_irqrestore(&i8253_lock, flags);
+ }
+
+ msleep(ms * 9 / 10);
+
+ raw_spin_lock_irqsave(&i8253_lock, flags);
+
+ /* stop beep
+ * clear bit 0-1 of port 61h
+ */
+ p61 = inb_p(SPEAKER_PORT);
+ if (p61 & 3)
+ outb(p61 & 0xFC, SPEAKER_PORT);
+
+ raw_spin_unlock_irqrestore(&i8253_lock, flags);
+
+ msleep(ms / 10);
+}
diff --git a/include/linux/play.h b/include/linux/play.h
new file mode 100644
index 000000000000..ae30cb8a0c1d
--- /dev/null
+++ b/include/linux/play.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * play.h - Definitions and headers for the aural error reporting framework.
+ *
+ * Copyright (C) 2019 Matteo Croce <[email protected]>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef _LINUX_PLAY_H
+#define _LINUX_PLAY_H
+
+#ifdef CONFIG_PLAY_LIB
+
+struct note {
+ unsigned int freq;
+ unsigned int dur;
+};
+
+void arch_play_one(unsigned int ms, unsigned int hz);
+
+#define play(notes, len) do { \
+ int i; \
+ for (i = 0; i < len; i++) \
+ arch_play_one(notes[i].dur, notes[i].freq); \
+ } while (0)
+
+#else
+
+#define play(n, l)
+
+#endif
+
+#endif
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 0d9e81779e37..10d04b266aef 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -992,6 +992,11 @@ config PANIC_TIMEOUT
value n > 0 will wait n seconds before rebooting, while a timeout
value n < 0 will reboot immediately.

+config PLAY_LIB
+ bool
+ depends on HAVE_PCSPKR_PLATFORM
+ default n
+
config SCHED_DEBUG
bool "Collect scheduler debugging info"
depends on DEBUG_KERNEL && PROC_FS
--
2.20.1

2019-04-01 10:26:42

by Matteo Croce

[permalink] [raw]
Subject: [PATCH 2/4] panic: use the aural error reporting framework to report panics

Use the new aural error reporting framework to signal kernel panic. The
error sound is emitted between the stack dump and the kexec jump.

Signed-off-by: Matteo Croce <[email protected]>
---
kernel/panic.c | 25 +++++++++++++++++++++++++
lib/Kconfig.debug | 10 ++++++++++
2 files changed, 35 insertions(+)

diff --git a/kernel/panic.c b/kernel/panic.c
index 0ae0d7332f12..360578e092e7 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -29,6 +29,7 @@
#include <linux/bug.h>
#include <linux/ratelimit.h>
#include <linux/debugfs.h>
+#include <linux/play.h>
#include <asm/sections.h>

#define PANIC_TIMER_STEP 100
@@ -57,6 +58,29 @@ ATOMIC_NOTIFIER_HEAD(panic_notifier_list);

EXPORT_SYMBOL(panic_notifier_list);

+#ifdef CONFIG_AUDIBLE_PANIC
+static struct note panic_sound[] = {
+ { 784, 400 },
+ { 784, 400 },
+ { 784, 400 },
+ { 622, 300 },
+ { 932, 100 },
+ { 784, 400 },
+ { 622, 300 },
+ { 932, 100 },
+ { 784, 800 },
+ { 1174, 400 },
+ { 1174, 400 },
+ { 1174, 400 },
+ { 1244, 300 },
+ { 932, 100 },
+ { 740, 400 },
+ { 622, 300 },
+ { 932, 100 },
+ { 784, 800 },
+};
+#endif
+
static long no_blink(int state)
{
return 0;
@@ -213,6 +237,7 @@ void panic(const char *fmt, ...)
if (!test_taint(TAINT_DIE) && oops_in_progress <= 1)
dump_stack();
#endif
+ play(panic_sound, ARRAY_SIZE(panic_sound));

/*
* If we have crashed and we have a crash kernel loaded let it handle
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 10d04b266aef..e5d187dfc74a 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -997,6 +997,16 @@ config PLAY_LIB
depends on HAVE_PCSPKR_PLATFORM
default n

+config AUDIBLE_PANIC
+ bool "Aural panic"
+ select PLAY_LIB
+ default n
+ help
+ If you say Y here, kernel panics will play a sound just
+ after the stacktrace and registers dump. The sound is played via
+ the system buzzer and not via any soundcard.
+ Not available on all platforms.
+
config SCHED_DEBUG
bool "Collect scheduler debugging info"
depends on DEBUG_KERNEL && PROC_FS
--
2.20.1

2019-04-01 10:26:51

by Matteo Croce

[permalink] [raw]
Subject: [PATCH 3/4] bug: use the aural error reporting framework to report warnings

Use the new aural error reporting framework to signal kernel bugs. Emit the
sound at the end of the __warn(), so the WARN_* are all covered.
If panic_on_warn is set, panic() will play its sound and never return,
so there is no risk to emit two sounds or the wrong one.

Signed-off-by: Matteo Croce <[email protected]>
---
kernel/panic.c | 18 ++++++++++++++++++
lib/Kconfig.debug | 10 ++++++++++
2 files changed, 28 insertions(+)

diff --git a/kernel/panic.c b/kernel/panic.c
index 360578e092e7..b87c4403924d 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -81,6 +81,22 @@ static struct note panic_sound[] = {
};
#endif

+#ifdef CONFIG_AUDIBLE_WARN
+static struct note warn_sound[] = {
+ { 440, 400 },
+ { 440, 300 },
+ { 440, 100 },
+ { 440, 400 },
+ { 523, 300 },
+ { 494, 100 },
+ { 494, 300 },
+ { 440, 100 },
+ { 440, 300 },
+ { 440, 100 },
+ { 440, 800 },
+};
+#endif
+
static long no_blink(int state)
{
return 0;
@@ -609,6 +625,8 @@ void __warn(const char *file, int line, void *caller, unsigned taint,

/* Just a warning, don't kill lockdep. */
add_taint(taint, LOCKDEP_STILL_OK);
+
+ play(warn_sound, ARRAY_SIZE(warn_sound));
}

#ifdef WANT_WARN_ON_SLOWPATH
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index e5d187dfc74a..909c271d283b 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1007,6 +1007,16 @@ config AUDIBLE_PANIC
the system buzzer and not via any soundcard.
Not available on all platforms.

+config AUDIBLE_WARN
+ bool "Aural warning"
+ select PLAY_LIB
+ default n
+ help
+ If you say Y here, warnings will play a sound just
+ after the stacktrace and registers dump. The sound is played via
+ the system buzzer and not via any soundcard.
+ Not available on all platforms.
+
config SCHED_DEBUG
bool "Collect scheduler debugging info"
depends on DEBUG_KERNEL && PROC_FS
--
2.20.1

2019-04-01 10:27:21

by Matteo Croce

[permalink] [raw]
Subject: [PATCH 5/4] procfs: utility handler to trigger different errors

Add a /proc/crashtest handler which triggers different kernel errors.
Just write a single character (if many are written, only the first one
is read), to trigger different errors:
- p: raise a kernel panic
- w: generate a warning
- o: raise an oops
The handler permissions are set to 0220 to avoid non root users to crash
the system.

Signed-off-by: Matteo Croce <[email protected]>
---
fs/proc/Makefile | 1 +
fs/proc/crashtest.c | 43 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 44 insertions(+)
create mode 100644 fs/proc/crashtest.c

diff --git a/fs/proc/Makefile b/fs/proc/Makefile
index ead487e80510..df99d3245ad9 100644
--- a/fs/proc/Makefile
+++ b/fs/proc/Makefile
@@ -15,6 +15,7 @@ proc-$(CONFIG_TTY) += proc_tty.o
proc-y += cmdline.o
proc-y += consoles.o
proc-y += cpuinfo.o
+proc-y += crashtest.o
proc-y += devices.o
proc-y += interrupts.o
proc-y += loadavg.o
diff --git a/fs/proc/crashtest.c b/fs/proc/crashtest.c
new file mode 100644
index 000000000000..ad7d21cc9d98
--- /dev/null
+++ b/fs/proc/crashtest.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/uaccess.h>
+
+static ssize_t crashtest_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ char cmd;
+
+ if (!count)
+ return 0;
+
+ if (get_user(cmd, buf))
+ return -EFAULT;
+
+ switch (cmd) {
+ case 'p':
+ panic("crashtest");
+ break;
+ case 'w':
+ WARN(1, "crashtest");
+ break;
+ case 'o':
+ *(int*)0 = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static const struct file_operations proc_crashtest_ops = {
+ .write = crashtest_write,
+};
+
+static int __init proc_crashtest_init(void)
+{
+ return !proc_create("crashtest", 0220, NULL, &proc_crashtest_ops);
+}
+fs_initcall(proc_crashtest_init);
--
2.20.1

2019-04-01 10:28:14

by Matteo Croce

[permalink] [raw]
Subject: [PATCH 4/4] oops: use the aural error reporting framework to report oopses

Use the new aural error reporting framework when reporting an oops. The
sound is emitted at the end of oops_exit(), to avoid interfering with other
oops actions, like stack dump.

Signed-off-by: Matteo Croce <[email protected]>
---
kernel/panic.c | 18 ++++++++++++++++++
lib/Kconfig.debug | 10 ++++++++++
2 files changed, 28 insertions(+)

diff --git a/kernel/panic.c b/kernel/panic.c
index b87c4403924d..ea34f93ce410 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -97,6 +97,23 @@ static struct note warn_sound[] = {
};
#endif

+#ifdef CONFIG_AUDIBLE_OOPS
+static struct note oops_sound[] = {
+ { 494, 100 },
+ { 698, 100 },
+ { 0, 100 },
+ { 698, 100 },
+ { 698, 133 },
+ { 659, 133 },
+ { 587, 133 },
+ { 523, 100 },
+ { 330, 100 },
+ { 262, 100 },
+ { 330, 100 },
+ { 262, 100 },
+};
+#endif
+
static long no_blink(int state)
{
return 0;
@@ -575,6 +592,7 @@ void oops_exit(void)
do_oops_enter_exit();
print_oops_end_marker();
kmsg_dump(KMSG_DUMP_OOPS);
+ play(oops_sound, ARRAY_SIZE(oops_sound));
}

struct warn_args {
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 909c271d283b..74745ef386ce 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1017,6 +1017,16 @@ config AUDIBLE_WARN
the system buzzer and not via any soundcard.
Not available on all platforms.

+config AUDIBLE_OOPS
+ bool "Aural oops"
+ select PLAY_LIB
+ default n
+ help
+ If you say Y here, oops will play a sound just
+ after the stacktrace and registers dump. The sound is played via
+ the system buzzer and not via any soundcard.
+ Not available on all platforms.
+
config SCHED_DEBUG
bool "Collect scheduler debugging info"
depends on DEBUG_KERNEL && PROC_FS
--
2.20.1

2019-04-01 11:04:24

by Peter Zijlstra

[permalink] [raw]
Subject: Re: [PATCH 0/4] Introduce the aural error reporting framework

On Mon, Apr 01, 2019 at 12:24:51PM +0200, Matteo Croce wrote:
> The buzzer driver is simple, requires just a few register writes to work,
> the hardware is extremely cheap and is already present on most machines.

What, no morse-code register dumps?

2019-04-01 13:54:38

by Emiliano Russo

[permalink] [raw]
Subject: Re: [PATCH 0/4] Introduce the aural error reporting framework


Il 01/04/19 12:24, Matteo Croce ha scritto:

> These are all cases when the aural errors framework comes to help. This
> framework adds to the kernel a generic library to play sounds, which can
> be used to report errors or generic events.

hello Matteo,

this reminds me of a hack that Mr. Ferruccio Zulian (chief system
architect for Olivetti, General Electric, Honeywell and IBM from 1965 to
1990) told us about during an interview we made for our computer art
exhibition "bin/art"

When testing the hardware of a new system, back in the mid-60s, the
engineers hooked audio output to circuitry for debugging purposes.

They kept in mind how a set of correctly executed operations
**literally** sounded like and therefore they were able to detect errors
in later executions when something sounded "wrong".

This was way more easy than looking at the light panels commonly used
for similar debugging activities, as listening to sounds does not force
you to be in a particular place, looking at a particular object.

As explained in the interview, an interesting side effect of this hack
led to the early computer music experiments with Pietro Grossi (a real
giant in contemporary and electronic music) that ended up in the
recording "GE-115 concerto" 7 inch vinyl, distributed as christmas gift
to all Olivetti/General Electric employees in 1967.

here's the link to a webpage with the interview (in italian)

https://binart.eu/ge-115-concerto/

and to the recording itself

side A: https://www.youtube.com/watch?v=CXosSsSekaU
side B: https://www.youtube.com/watch?v=bf8jMA_zizc


...so, what does this curious anectode say to us?

it looks like history is on the side of this patch :-)

hope it gets in the mainline code!


Ciao!
Emiliano Russo
---------------
Museo Interattivo di Archeologia Informatica (MIAI)
Museo dell'Informatica Funzionante (MusIF)

Computer Musea :-)

2019-04-02 10:20:36

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH 0/4] Introduce the aural error reporting framework

On Mon, 1 Apr 2019, Peter Zijlstra wrote:
> On Mon, Apr 01, 2019 at 12:24:51PM +0200, Matteo Croce wrote:
> > The buzzer driver is simple, requires just a few register writes to work,
> > the hardware is extremely cheap and is already present on most machines.
>
> What, no morse-code register dumps?

Aside of that, where is the android-app to customize and decode the
melodies?

I surely want to have the music theme of 'Once Upon a Time in the West' on
kernel crashes.

Thanks,

tglx




2019-04-02 12:02:49

by Matteo Croce

[permalink] [raw]
Subject: Re: [PATCH 0/4] Introduce the aural error reporting framework

On Tue, Apr 2, 2019 at 11:33 AM Thomas Gleixner <[email protected]> wrote:
>
> On Mon, 1 Apr 2019, Peter Zijlstra wrote:
> > On Mon, Apr 01, 2019 at 12:24:51PM +0200, Matteo Croce wrote:
> > > The buzzer driver is simple, requires just a few register writes to work,
> > > the hardware is extremely cheap and is already present on most machines.
> >
> > What, no morse-code register dumps?
>
> Aside of that, where is the android-app to customize and decode the
> melodies?
>
> I surely want to have the music theme of 'Once Upon a Time in the West' on
> kernel crashes.
>
> Thanks,
>
> tglx
>

Hi Thomas,

I'm a little rusty with Android programming, so I'll share the script
I use to convert notes to frequences.
With some awk magic it can turn notes into a C array, I hope that you
find it useful.

Bye,
--
Matteo Croce
per aspera ad upstream


Attachments:
notes2freq.sh (716.00 B)

2019-04-02 13:37:58

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH 0/4] Introduce the aural error reporting framework

Matteo,

On Tue, 2 Apr 2019, Matteo Croce wrote:
> On Tue, Apr 2, 2019 at 11:33 AM Thomas Gleixner <[email protected]> wrote:
> > Aside of that, where is the android-app to customize and decode the
> > melodies?
> >
> > I surely want to have the music theme of 'Once Upon a Time in the West' on
> > kernel crashes.
>
> I'm a little rusty with Android programming, so I'll share the script
> I use to convert notes to frequences.
> With some awk magic it can turn notes into a C array, I hope that you
> find it useful.

That's great. Just a few nitpicks on the patches themself. You want to
change msleep() to mdelay() in order to avoid "Scheduling while atomic"
noise and you want to have global serialization because interleaving "La
Paloma" from CPU1 and "Once Upon a Time in the West" from CPU2 sounds
really horrible.

Thanks,

tglx