linux/arch/i386/boot/tty.c
H. Peter Anvin b015124e56 [x86 setup] Volatilize asm() statements
asm() statements need to be volatile when:

a. They have side effects (other than value returned).
b. When the value returned can vary over time.
c. When they have ordering constraints that cannot be expressed to gcc.

In particular, the keyboard and timer reads were violating constraint (b),
which resulted in the keyboard/timeout poll getting
loop-invariant-removed when compiling with gcc 4.2.0.

Thanks to an anonymous bug reporter for pointing this out.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2007-08-23 13:03:25 -07:00

113 lines
1.9 KiB
C

/* -*- linux-c -*- ------------------------------------------------------- *
*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright 2007 rPath, Inc. - All Rights Reserved
*
* This file is part of the Linux kernel, and is made available under
* the terms of the GNU General Public License version 2.
*
* ----------------------------------------------------------------------- */
/*
* arch/i386/boot/tty.c
*
* Very simple screen I/O
* XXX: Probably should add very simple serial I/O?
*/
#include "boot.h"
/*
* These functions are in .inittext so they can be used to signal
* error during initialization.
*/
void __attribute__((section(".inittext"))) putchar(int ch)
{
unsigned char c = ch;
if (c == '\n')
putchar('\r'); /* \n -> \r\n */
/* int $0x10 is known to have bugs involving touching registers
it shouldn't. Be extra conservative... */
asm volatile("pushal; pushw %%ds; int $0x10; popw %%ds; popal"
: : "b" (0x0007), "c" (0x0001), "a" (0x0e00|ch));
}
void __attribute__((section(".inittext"))) puts(const char *str)
{
int n = 0;
while (*str) {
putchar(*str++);
n++;
}
}
/*
* Read the CMOS clock through the BIOS, and return the
* seconds in BCD.
*/
static u8 gettime(void)
{
u16 ax = 0x0200;
u16 cx, dx;
asm volatile("int $0x1a"
: "+a" (ax), "=c" (cx), "=d" (dx)
: : "ebx", "esi", "edi");
return dx >> 8;
}
/*
* Read from the keyboard
*/
int getchar(void)
{
u16 ax = 0;
asm volatile("int $0x16" : "+a" (ax));
return ax & 0xff;
}
static int kbd_pending(void)
{
u8 pending;
asm volatile("int $0x16; setnz %0"
: "=rm" (pending)
: "a" (0x0100));
return pending;
}
void kbd_flush(void)
{
for (;;) {
if (!kbd_pending())
break;
getchar();
}
}
int getchar_timeout(void)
{
int cnt = 30;
int t0, t1;
t0 = gettime();
while (cnt) {
if (kbd_pending())
return getchar();
t1 = gettime();
if (t0 != t1) {
cnt--;
t0 = t1;
}
}
return 0; /* Timeout! */
}