All of lore.kernel.org
 help / color / mirror / Atom feed
* Compressed kernel image
@ 2002-09-16 14:16 Johannes Stezenbach
  0 siblings, 0 replies; only message in thread
From: Johannes Stezenbach @ 2002-09-16 14:16 UTC (permalink / raw)
  To: linux-mips

[-- Attachment #1: Type: text/plain, Size: 1161 bytes --]

Hi,

for the embedded Linux project I'm working on I needed the
ability to boot a compressed kernel image from ROM, i.e.
uncompress it to RAM and jump to the kernel entry.

So I took some parts from arch/i386/boot/compressed,
and some from linux-mips.sf.net/arch/mips/zboot/ and
hacked up something which works for me.

The appended patch is incomplete as I removed anything
specific to my platform. To use it for a different platform
you would need:

- A head.S which works for your board. Depending on what
  your bootloader does, you probably don't need the
  cache flushing stuff.
- For debug output, you need a putc() implementation; maybe
  the included uart16550.c works for you. If you think you don't
  need to debug anything ;-), you could use a dummy putc().
- Set some configuration variables in the Makefile. I tested
  both booting from ROM and loading the zImage to RAM, then
  uncompressing to some different area in RAM.
  Note: For my platform I allocate a 2MB frame buffer at
  0x80002000 in unified memory, so reuse this space
  for uncompressing the zImage.

I hope the patch is of use to someone. Comments are welcome.


Regards,
Johannes

[-- Attachment #2: linux-oss-zimage.patch --]
[-- Type: text/plain, Size: 17351 bytes --]

diff -urN linux-oss.orig/arch/mips/Makefile linux-oss/arch/mips/Makefile
--- linux-oss.orig/arch/mips/Makefile	2002-09-09 21:30:11.000000000 +0200
+++ linux-oss/arch/mips/Makefile	2002-09-16 14:55:40.000000000 +0200
@@ -475,6 +475,11 @@
 endif
 
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+MAKEZBOOT = $(MAKE) -C arch/$(ARCH)/boot/compressed
+
+BOOT_TARGETS = zImage
+$(BOOT_TARGETS):  vmlinux
+	@$(MAKEZBOOT) $@
 
 vmlinux.ecoff: vmlinux
 	@$(MAKEBOOT) $@
@@ -484,6 +489,7 @@
 	rm -f arch/$(ARCH)/ld.script
 	$(MAKE) -C arch/$(ARCH)/tools clean
 	$(MAKE) -C arch/mips/baget clean
+	$(MAKE) -C arch/$(ARCH)/boot/compressed clean
 
 archmrproper:
 	@$(MAKEBOOT) mrproper
diff -urN linux-oss.orig/arch/mips/boot/compressed/Makefile linux-oss/arch/mips/boot/compressed/Makefile
--- linux-oss.orig/arch/mips/boot/compressed/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-oss/arch/mips/boot/compressed/Makefile	2002-09-16 15:01:13.000000000 +0200
@@ -0,0 +1,74 @@
+#
+# linux/arch/mips/boot/compressed/Makefile
+#
+# create a compressed zImage from the original vmlinux
+#
+
+HEAD = head.o
+SYSTEM = $(TOPDIR)/vmlinux
+
+ZLDFLAGS = -e zstartup -T $(TOPDIR)/arch/mips/ld.script
+
+all: $(TOPDIR)/zImage
+
+##################################################################
+# board configuration
+##################################################################
+
+ifdef CONFIG_FOOBAR // board specific
+
+# ZIMAGE_OFFSET is the load offset of the compression loader
+ifdef BOOT_FROM_ROM
+# zImage in ROM after boot code
+ZIMAGE_OFFSET := 0x9fc20000
+ZBSS          := -Tbss 0x80002000
+else
+# for loading in RAM
+ZIMAGE_OFFSET := 0x81000000
+endif
+
+# *MUST* match LOADADDR from arch/mips/Makefile
+LOADADDR      := 0x80202000
+KERNEL_ENTRY  = $(shell $(OBJDUMP) -f $(SYSTEM) | sed -n -e 's/^start address //p')
+# working space for gunzip:
+FREE_RAM      := 0x80080000
+END_RAM       := 0x80200000
+# putc config
+PUTC_IMPL     := uart16550.o
+uart16550.o: uart16550.c Makefile
+	$(CC) $(CFLAGS) -DBASE=0xb2001000 -DMAX_BAUD=1152000 -DREG_OFFSET=0x10 -c uart16550.c
+endif
+
+##################################################################
+
+OBJECTS = $(HEAD) misc.o $(PUTC_IMPL)
+
+ZLINKFLAGS = -Ttext $(ZIMAGE_OFFSET) $(ZBSS) $(ZLDFLAGS)
+
+.PHONY: zImage
+zImage: $(TOPDIR)/zImage
+
+$(TOPDIR)/zImage: piggy.o $(OBJECTS)
+	$(LD) $(ZLINKFLAGS) -o $(TOPDIR)/zImage $(OBJECTS) piggy.o
+
+head.o: head.S Makefile $(SYSTEM)
+	$(CC) $(AFLAGS) -DKERNEL_ENTRY=$(KERNEL_ENTRY) -c head.S
+
+comma	:= ,
+
+misc.o: misc.c Makefile
+	$(CC) $(CFLAGS) -DLOADADDR=$(LOADADDR) \
+	    -DFREE_RAM=$(FREE_RAM) -DEND_RAM=$(END_RAM) \
+	    -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c misc.c
+
+piggy.o:	$(SYSTEM)
+	tmppiggy=_tmp_$$$$piggy; \
+	rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \
+	$(OBJCOPY) -S -O binary -R .note -R .comment $(SYSTEM) $$tmppiggy; \
+	gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \
+	echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \
+	$(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-tradbigmips -T $$tmppiggy.lnk; \
+	rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk
+
+clean:
+	rm -f $(TOPDIR)/zImage _tmp_* *.o
diff -urN linux-oss.orig/arch/mips/boot/compressed/head.S linux-oss/arch/mips/boot/compressed/head.S
--- linux-oss.orig/arch/mips/boot/compressed/head.S	1970-01-01 01:00:00.000000000 +0100
+++ linux-oss/arch/mips/boot/compressed/head.S	2002-09-16 15:11:48.000000000 +0200
@@ -0,0 +1,100 @@
+/*
+ * arch/mips/boot/compressed/head.S
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1994, 1995 Waldorf Electronics
+ * Written by Ralf Baechle and Andreas Busse
+ * Copyright (C) 1995 - 1999 Ralf Baechle
+ * Copyright (C) 1996 Paul M. Antoine
+ * Modified for DECStation and hence R3000 support by Paul M. Antoine
+ * Further modifications by David S. Miller and Harald Koerfgen
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ *
+ * Head.S contains the MIPS exception handler and startup code.
+ *
+ **************************************************************************
+ *  9 Nov, 2000.
+ *  Added Cache Error exception handler and SBDDP EJTAG debug exception.
+ *
+ *  Kevin Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
+ *  Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+ **************************************************************************
+ * 08/2002 modified for zImage boot from ROM
+ * Johannes Stezenbach <js@convergence.de>
+ */
+
+
+#include <linux/config.h>
+#include <linux/threads.h>
+
+#include <asm/asm.h>
+#include <asm/cacheops.h>
+#include <asm/mipsregs.h>
+#include <asm/offset.h>
+#include <asm/cachectl.h>
+#include <asm/regdef.h>
+
+#define IndexInvalidate_I       0x00
+
+	.set noreorder
+	.cprestore
+	LEAF(zstartup)
+zstartup:
+
+        la      sp, .stack
+	move	s0, a0
+	move	s1, a1
+	move	s2, a2
+	move	s3, a3
+
+	/* Clear BSS */
+	/* Note: when zImage is in ROM, _edata and _bss point to
+	 * ROM space even when using -Tbss on the linker command line;
+	 * maybe ld.script needs to be corrected.
+	 */
+	la	a0, .stack
+	la	a2, _end
+1:	sw	zero, 0(a0)
+	bne	a2, a0, 1b
+	addu	a0, 4
+
+	/* flush the I-Cache */
+	li	k0, 0x80000000  # start address
+	li	k1, 0x80004000  # end address (16KB I-Cache)
+	subu	k1, 128
+
+2:
+	.set mips3
+	cache	IndexInvalidate_I, 0(k0)
+	cache	IndexInvalidate_I, 32(k0)
+	cache	IndexInvalidate_I, 64(k0)
+	cache	IndexInvalidate_I, 96(k0)
+	.set mips0
+
+	bne	k0, k1, 2b
+	addu	k0, k0, 128
+	/* done */
+
+	la	ra, 3f
+	la	k0, decompress_kernel
+	jr	k0
+	nop
+3:
+
+	move	a0, s0
+	move	a1, s1
+	move	a2, s2
+	move	a3, s3
+	li	k0, KERNEL_ENTRY
+	jr	k0
+	nop
+4:
+	b 4b
+	END(zstartup)
+
+	.bss
+	.fill 0x2000
+	EXPORT(.stack)
diff -urN linux-oss.orig/arch/mips/boot/compressed/misc.c linux-oss/arch/mips/boot/compressed/misc.c
--- linux-oss.orig/arch/mips/boot/compressed/misc.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-oss/arch/mips/boot/compressed/misc.c	2002-08-06 19:19:11.000000000 +0200
@@ -0,0 +1,311 @@
+/*
+ * arch/mips/boot/misc.c
+ *
+ * This is a collection of several routines from gzip-1.0.3
+ * adapted for Linux.
+ *
+ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
+ * puts by Nick Holloway 1993, better puts by Martin Mares 1995
+ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
+ *
+ * Modified by RidgeRun Inc.
+ *
+ * 08/2002 modified for booting zImage from ROM
+ * Johannes Stezenbach <js@convergence.de>
+ * (All statically initialized data is read only, all data which needs to be
+ * in RAM must not be statically initialized.)
+ */
+
+#define ZDEBUG 1
+
+#include <linux/types.h>
+
+/*
+ * gzip declarations
+ */
+#define OF(args)  args
+#define STATIC static
+#define memzero(s, n)     memset ((s), 0, (n))
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned long ulg;
+#define WSIZE 0x8000		/* Window size must be at least 32k, */
+				/* and a power of two */
+static uch *inbuf;		/* input buffer */
+static uch window[WSIZE];	/* Sliding window buffer */
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01	/* bit 0 set: file probably ASCII text */
+#define CONTINUATION 0x02	/* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD  0x04	/* bit 2 set: extra field present */
+#define ORIG_NAME    0x08	/* bit 3 set: original file name present */
+#define COMMENT      0x10	/* bit 4 set: file comment present */
+#define ENCRYPTED    0x20	/* bit 5 set: file is encrypted */
+#define RESERVED     0xC0	/* bit 6,7:   reserved */
+
+
+static unsigned insize;	/* valid bytes in inbuf */
+static unsigned inptr;	/* index of next byte to be processed in inbuf */
+static unsigned outcnt;	/* bytes in output buffer */
+
+void variable_init(void);
+static void puts(const char *);
+extern void putc_init(void);
+extern void putc(unsigned char c);
+static int fill_inbuf(void);
+static void flush_window(void);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+
+extern char input_data[];
+extern int input_len;
+
+
+void int2hex(unsigned long val)
+{
+        unsigned char buf[10];
+        int i;
+        for (i = 7;  i >= 0;  i--)
+        {
+                buf[i] = "0123456789ABCDEF"[val & 0x0F];
+                val >>= 4;
+        }
+        buf[8] = '\0';
+        puts(buf);
+}
+
+static unsigned long byte_count;
+
+int get_byte(void)
+{
+#if ZDEBUG > 1
+	static int printCnt;
+#endif
+	unsigned char c = (inptr < insize ? inbuf[inptr++] : fill_inbuf());
+	byte_count++;
+
+#if ZDEBUG > 1
+	if (printCnt++ < 32)
+	{
+	  puts("byte count = ");
+	  int2hex(byte_count);
+	  puts(" byte val = ");
+	  int2hex(c);
+	  puts("\n");
+	}
+#endif
+	return c;
+}
+
+/* Diagnostic functions */
+#ifdef DEBUG
+#  define Assert(cond,msg) {if(!(cond)) error(msg);}
+#  define Trace(x) fprintf x
+#  define Tracev(x) {if (verbose) fprintf x ;}
+#  define Tracevv(x) {if (verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+/*
+ * This is set up by the setup-routine at boot-time
+ */
+
+static long bytes_out;
+static uch *output_data;
+static unsigned long output_ptr;
+
+
+static void *malloc(int size);
+static void free(void *where);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+
+static unsigned long free_mem_ptr;
+static unsigned long free_mem_end_ptr;
+
+#include "../../../../lib/inflate.c"
+
+static void *malloc(int size)
+{
+	void *p;
+
+	if (size < 0)
+		error("Malloc error\n");
+	if (free_mem_ptr <= 0) error("Memory error\n");
+
+	free_mem_ptr = (free_mem_ptr + 3) & ~3;	/* Align */
+
+	p = (void *) free_mem_ptr;
+	free_mem_ptr += size;
+
+	if (free_mem_ptr >= free_mem_end_ptr)
+		error("\nOut of memory\n");
+
+	return p;
+}
+
+static void free(void *where)
+{				/* Don't care */
+}
+
+static void gzip_mark(void **ptr)
+{
+	*ptr = (void *) free_mem_ptr;
+}
+
+static void gzip_release(void **ptr)
+{
+	free_mem_ptr = (long) *ptr;
+}
+
+static void puts(const char *s)
+{
+	while (*s) {
+		if (*s == 10)
+			putc(13);
+		putc(*s++);
+	}
+}
+
+void *memset(void *s, int c, size_t n)
+{
+	int i;
+	char *ss = (char *) s;
+
+	for (i = 0; i < n; i++)
+		ss[i] = c;
+	return s;
+}
+
+void *memcpy(void *__dest, __const void *__src, size_t __n)
+{
+	int i;
+	char *d = (char *) __dest, *s = (char *) __src;
+
+	for (i = 0; i < __n; i++)
+		d[i] = s[i];
+	return __dest;
+}
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty
+ * and at least one byte is really needed.
+ */
+static int fill_inbuf(void)
+{
+	if (insize != 0) {
+		error("ran out of input data\n");
+	}
+
+	inbuf = input_data;
+	insize = input_len;
+	inptr = 1;
+	return inbuf[0];
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+static void flush_window(void)
+{
+	ulg c = crc;		/* temporary variable */
+	unsigned n;
+	uch *in, *out, ch;
+
+	in = window;
+	out = &output_data[output_ptr];
+	for (n = 0; n < outcnt; n++) {
+		ch = *out++ = *in++;
+		c = crc_32_tab[((int) c ^ ch) & 0xff] ^ (c >> 8);
+	}
+	crc = c;
+	bytes_out += (ulg) outcnt;
+	output_ptr += (ulg) outcnt;
+	outcnt = 0;
+}
+
+void check_mem(void)
+{
+	int i;
+
+	puts("\ncplens = ");
+	for (i = 0; i < 10; i++) {
+		int2hex(cplens[i]);
+		puts(" ");
+	}
+	puts("\ncplext = ");
+	for (i = 0; i < 10; i++) {
+		int2hex(cplext[i]);
+		puts(" ");
+	}
+	puts("\nborder = ");
+	for (i = 0; i < 10; i++) {
+		int2hex(border[i]);
+		puts(" ");
+	}
+	puts("\n");
+}
+
+static void error(char *x)
+{
+	check_mem();
+	puts("\n\n");
+	puts(x);
+	puts("byte_count = ");
+	int2hex(byte_count);
+	puts("\n");
+	puts("\n\n -- System halted");
+	while (1);		/* Halt */
+}
+
+void variable_init(void)
+{
+	byte_count = 0;
+	output_data = (char *) LOADADDR;
+	free_mem_ptr = FREE_RAM;
+	free_mem_end_ptr = END_RAM;
+#if ZDEBUG
+	puts("variable_init:\n");
+	int2hex((unsigned long)output_data); puts("\n");
+	int2hex(free_mem_ptr); puts("\n");
+	int2hex(free_mem_end_ptr); puts("\n");
+	int2hex((unsigned long)input_data); puts("\n");
+	int2hex(input_len); puts("\n");
+#endif
+}
+
+int decompress_kernel(void)
+{
+#if ZDEBUG
+	//check_mem();
+	unsigned long *p = (unsigned long *)LOADADDR;
+#endif
+
+	putc_init();
+	variable_init();
+
+	makecrc();
+	puts("Uncompressing Linux... \n");
+	gunzip();		// ...see inflate.c
+	puts("Ok, booting the kernel.\n");
+
+#if ZDEBUG
+	int2hex(p[0]); puts("\n");
+	int2hex(p[1]); puts("\n");
+	int2hex(p[2]); puts("\n");
+	int2hex(p[3]); puts("\n");
+#endif
+
+	return 0;
+}
diff -urN linux-oss.orig/arch/mips/boot/compressed/uart16550.c linux-oss/arch/mips/boot/compressed/uart16550.c
--- linux-oss.orig/arch/mips/boot/compressed/uart16550.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-oss/arch/mips/boot/compressed/uart16550.c	2002-09-16 15:16:38.000000000 +0200
@@ -0,0 +1,141 @@
+/*
+ * 16550 uart routines.
+ * based on something similar to arch/mips/vr4181/osprey/dbg_io.c
+ * Copyright (C) 2001 MontaVista Software Inc.
+ * Author: jsun@mvista.com or jsun@junsun.net
+ */
+#include <linux/config.h>
+#include <asm/io.h>
+
+/* === CONFIG === */
+
+/*
+ * #define BASE			0xb2001000
+ * #define MAX_BAUD		1152000
+ * #define REG_OFFSET		0x10
+ */
+#if (!defined(BASE) || !defined(MAX_BAUD) || !defined(REG_OFFSET))
+#error You must define BASE, MAX_BAUD and REG_OFFSET in the Makefile.
+#endif
+
+#ifndef INIT_SERIAL_PORT
+#define INIT_SERIAL_PORT	1
+#endif
+
+#ifndef DEFAULT_BAUD
+#define DEFAULT_BAUD		UART16550_BAUD_115200
+#endif
+#ifndef DEFAULT_PARITY
+#define DEFAULT_PARITY		UART16550_PARITY_NONE
+#endif
+#ifndef DEFAULT_DATA
+#define DEFAULT_DATA		UART16550_DATA_8BIT
+#endif
+#ifndef DEFAULT_STOP
+#define DEFAULT_STOP		UART16550_STOP_1BIT
+#endif
+
+/* === END OF CONFIG === */
+
+typedef         unsigned char uint8;
+typedef         unsigned int  uint32;
+
+#define         UART16550_BAUD_2400             2400
+#define         UART16550_BAUD_4800             4800
+#define         UART16550_BAUD_9600             9600
+#define         UART16550_BAUD_19200            19200
+#define         UART16550_BAUD_38400            38400
+#define         UART16550_BAUD_57600            57600
+#define         UART16550_BAUD_115200           115200
+
+#define         UART16550_PARITY_NONE           0
+#define         UART16550_PARITY_ODD            0x08
+#define         UART16550_PARITY_EVEN           0x18
+#define         UART16550_PARITY_MARK           0x28
+#define         UART16550_PARITY_SPACE          0x38
+
+#define         UART16550_DATA_5BIT             0x0
+#define         UART16550_DATA_6BIT             0x1
+#define         UART16550_DATA_7BIT             0x2
+#define         UART16550_DATA_8BIT             0x3
+
+#define         UART16550_STOP_1BIT             0x0
+#define         UART16550_STOP_2BIT             0x4
+
+/* register offset */
+#define		OFS_RCV_BUFFER		(0*REG_OFFSET)
+#define		OFS_TRANS_HOLD		(0*REG_OFFSET)
+#define		OFS_SEND_BUFFER		(0*REG_OFFSET)
+#define		OFS_INTR_ENABLE		(1*REG_OFFSET)
+#define		OFS_INTR_ID		(2*REG_OFFSET)
+#define		OFS_DATA_FORMAT		(3*REG_OFFSET)
+#define		OFS_LINE_CONTROL	(3*REG_OFFSET)
+#define		OFS_MODEM_CONTROL	(4*REG_OFFSET)
+#define		OFS_RS232_OUTPUT	(4*REG_OFFSET)
+#define		OFS_LINE_STATUS		(5*REG_OFFSET)
+#define		OFS_MODEM_STATUS	(6*REG_OFFSET)
+#define		OFS_RS232_INPUT		(6*REG_OFFSET)
+#define		OFS_SCRATCH_PAD		(7*REG_OFFSET)
+
+#define		OFS_DIVISOR_LSB		(0*REG_OFFSET)
+#define		OFS_DIVISOR_MSB		(1*REG_OFFSET)
+
+#define		UART16550_READ(y)    (*((volatile uint8*)(BASE + y)))
+#define		UART16550_WRITE(y, z)  ((*((volatile uint8*)(BASE + y))) = z)
+
+static void Uart16550Init(uint32 baud, uint8 data, uint8 parity, uint8 stop)
+{
+	/* disable interrupts */
+	UART16550_WRITE(OFS_LINE_CONTROL, 0x0);
+	UART16550_WRITE(OFS_INTR_ENABLE, 0);
+
+	/* set up baud rate */
+	{
+		uint32 divisor;
+
+		/* set DIAB bit */
+		UART16550_WRITE(OFS_LINE_CONTROL, 0x80);
+
+		/* set divisor */
+		divisor = MAX_BAUD / baud;
+		UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff);
+		UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00)>>8);
+
+		/* clear DIAB bit */
+		UART16550_WRITE(OFS_LINE_CONTROL, 0x0);
+	}
+
+	/* set data format */
+	UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop);
+}
+
+
+void
+putc_init(void)
+{
+#if INIT_SERIAL_PORT
+	Uart16550Init(DEFAULT_BAUD, DEFAULT_DATA, DEFAULT_PARITY, DEFAULT_STOP);
+#endif
+}
+
+void
+putc(unsigned char c)
+{
+	while ((UART16550_READ(OFS_LINE_STATUS) &0x20) == 0);
+	UART16550_WRITE(OFS_SEND_BUFFER, c);
+}
+
+#if 0
+unsigned char
+getc(void)
+{
+	while((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0);
+	return UART16550_READ(OFS_RCV_BUFFER);
+}
+
+int
+tstc(void)
+{
+	return((UART16550_READ(OFS_LINE_STATUS) & 0x01) != 0);
+}
+#endif

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2002-09-16 14:16 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-09-16 14:16 Compressed kernel image Johannes Stezenbach

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.