From cb0510ebcfb6fae05628ef94027f2f2c744498aa Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 6 May 2015 15:24:43 -0300 Subject: [PATCH] x86: Disable NMI while initializing RTC According to [1], we should disable non-maskable and maskable interrupts while initializing RTC. Otherwise, the RTC may be left in an undefined state (non-functional) if an interrupt occurs. Currently, maskable interrupts are already disabled, but NMI is not. This patch adds helpers APIs to enable/disable non-maskable interrupts (NMI) and changes rtc_init() to disable NMI while initializing the RTC. NMI enable/disable code is legacy-PC specific therefore it was put in driver/legacy_pc/ directory. Regarding the RTC initialization changes, just calling nmi_disable() and nmi_enable is not enough since NMI and RTC share the same IO port. So We should also set the NMI_ENABLE bit while selecting the RTC_INDEX. Additionally, the nmi_disable() call is not strictly required since we set the NMI_ENABLE bit while selecting the RTC_INDEX. However, to make clear hat we are disabling NMI and to improve readability (by matching NMI disable/enable), the nmi_disable() call was purposely used. [1] http://wiki.osdev.org/RTC --- cpu/x86/Makefile.x86_quarkX1000 | 2 +- cpu/x86/drivers/legacy_pc/nmi.c | 47 +++++++++++++++++++++++++++++++++ cpu/x86/drivers/legacy_pc/nmi.h | 38 ++++++++++++++++++++++++++ cpu/x86/drivers/legacy_pc/rtc.c | 13 ++++++--- 4 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 cpu/x86/drivers/legacy_pc/nmi.c create mode 100644 cpu/x86/drivers/legacy_pc/nmi.h diff --git a/cpu/x86/Makefile.x86_quarkX1000 b/cpu/x86/Makefile.x86_quarkX1000 index b7b6966b3..630d33804 100644 --- a/cpu/x86/Makefile.x86_quarkX1000 +++ b/cpu/x86/Makefile.x86_quarkX1000 @@ -2,6 +2,6 @@ include $(CONTIKI)/cpu/x86/Makefile.x86_common CONTIKI_CPU_DIRS += drivers/legacy_pc init/legacy_pc -CONTIKI_SOURCEFILES += bootstrap_quarkX1000.S rtc.c pit.c pic.c irq.c +CONTIKI_SOURCEFILES += bootstrap_quarkX1000.S rtc.c pit.c pic.c irq.c nmi.c LINKERSCRIPT = $(CONTIKI)/cpu/x86/quarkX1000.ld diff --git a/cpu/x86/drivers/legacy_pc/nmi.c b/cpu/x86/drivers/legacy_pc/nmi.c new file mode 100644 index 000000000..e57d93325 --- /dev/null +++ b/cpu/x86/drivers/legacy_pc/nmi.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "helpers.h" + +#define NMI_ENABLE_PORT 0x70 + +void +nmi_enable(void) +{ + uint8_t value = inb(NMI_ENABLE_PORT); + outb(NMI_ENABLE_PORT, value & ~BIT(8)); +} +/*---------------------------------------------------------------------------*/ +void +nmi_disable(void) +{ + uint8_t value = inb(NMI_ENABLE_PORT); + outb(NMI_ENABLE_PORT, value | BIT(8)); +} diff --git a/cpu/x86/drivers/legacy_pc/nmi.h b/cpu/x86/drivers/legacy_pc/nmi.h new file mode 100644 index 000000000..3b5544cf0 --- /dev/null +++ b/cpu/x86/drivers/legacy_pc/nmi.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef NMI_H +#define NMI_H + +void nmi_enable(void); + +void nmi_disable(void); + +#endif /* NMI_H */ diff --git a/cpu/x86/drivers/legacy_pc/rtc.c b/cpu/x86/drivers/legacy_pc/rtc.c index 7ba6dccc3..cf059315b 100644 --- a/cpu/x86/drivers/legacy_pc/rtc.c +++ b/cpu/x86/drivers/legacy_pc/rtc.c @@ -30,6 +30,7 @@ #include "drivers/legacy_pc/rtc.h" #include "drivers/legacy_pc/pic.h" +#include "drivers/legacy_pc/nmi.h" #include "helpers.h" #include "interrupt.h" @@ -72,19 +73,23 @@ rtc_init(rtc_frequency_t frequency, void (*callback)(void)) SET_INTERRUPT_HANDLER(RTC_INT, 0, rtc_handler); + nmi_disable(); + /* Select interrupt period to 7.8125 ms */ - outb(RTC_INDEX_REGISTER, 0x0A); + outb(RTC_INDEX_REGISTER, 0x8A); reg_a = inb(RTC_TARGET_REGISTER); reg_a &= 0xF0; reg_a |= frequency; - outb(RTC_INDEX_REGISTER, 0x0A); + outb(RTC_INDEX_REGISTER, 0x8A); outb(RTC_TARGET_REGISTER, reg_a); /* Enable periodic interrupt */ - outb(RTC_INDEX_REGISTER, 0x0B); + outb(RTC_INDEX_REGISTER, 0x8B); reg_b = inb(RTC_TARGET_REGISTER); - outb(RTC_INDEX_REGISTER, 0x0B); + outb(RTC_INDEX_REGISTER, 0x8B); outb(RTC_TARGET_REGISTER, reg_b | BIT(6)); + nmi_enable(); + pic_unmask_irq(RTC_IRQ); }