[syslinux:elflink] core: Reimplement lots asm code in C

syslinux-bot for Matt Fleming matt.fleming at intel.com
Sat Dec 17 21:19:35 PST 2011


Commit-ID:  9f51b69d7c0500e04b3c404bb5138a9234810035
Gitweb:     http://www.syslinux.org/commit/9f51b69d7c0500e04b3c404bb5138a9234810035
Author:     Matt Fleming <matt.fleming at intel.com>
AuthorDate: Tue, 18 Oct 2011 13:13:06 +0100
Committer:  Matt Fleming <matt.fleming at intel.com>
CommitDate: Thu, 1 Dec 2011 13:14:05 +0000

core: Reimplement lots asm code in C

There is an awful lot of code currently implemented in assembly when
it could just as easily be implemented in C. Having it in C makes it
much easier to share code between the BIOS and forthcoming EFI
firmware backend. The following code fragments have been rewritten,

  - timer initialisation
  - adjust_screen()
  - check_esapes() and mem_init()
  - conio.inc
  - plaincon.inc
  - cleanup.inc
  - serirq.inc
  - font.inc
  - graphics
  - writehex

Signed-off-by: Matt Fleming <matt.fleming at intel.com>

---
 com32/elflink/ldlinux/readconfig.c |   49 +---
 core/abort.inc                     |   84 -----
 core/cleanup.c                     |   46 +++
 core/cleanup.inc                   |   60 ----
 core/comboot.inc                   |   14 +-
 core/common.inc                    |    3 -
 core/conio.c                       |  600 ++++++++++++++++++++++++++++++++++++
 core/conio.inc                     |  435 --------------------------
 core/diskfs.inc                    |    2 -
 core/extern.inc                    |   21 ++
 core/font.c                        |  195 ++++++++++++
 core/font.inc                      |  153 ---------
 core/graphics.c                    |  382 +++++++++++++++++++++++
 core/graphics.inc                  |  353 ---------------------
 core/idle.inc                      |    5 +-
 core/include/bios.h                |  105 +++++++
 core/include/core.h                |    2 +
 core/init.c                        |   77 +++++
 core/init.inc                      |   60 +----
 core/isolinux.asm                  |   16 +
 core/plaincon.c                    |   32 ++
 core/plaincon.inc                  |   24 --
 core/pm.inc                        |    3 +-
 core/pxelinux.asm                  |   17 +-
 core/serirq.c                      |  204 ++++++++++++
 core/serirq.inc                    |  221 -------------
 core/timer.inc                     |    3 +
 core/ui.inc                        |   10 +-
 core/writehex.c                    |   70 +++++
 29 files changed, 1803 insertions(+), 1443 deletions(-)

diff --git a/com32/elflink/ldlinux/readconfig.c b/com32/elflink/ldlinux/readconfig.c
index 5bf6f42..60448c4 100644
--- a/com32/elflink/ldlinux/readconfig.c
+++ b/com32/elflink/ldlinux/readconfig.c
@@ -721,7 +721,7 @@ extern uint8_t SerialNotice;
 
 extern void sirq_cleanup_nowipe(void);
 extern void sirq_install(void);
-extern void write_serial_str(void);
+extern void write_serial_str(char *);
 
 static inline void io_delay(void)
 {
@@ -729,9 +729,9 @@ static inline void io_delay(void)
 	outb(0, 0x80);
 }
 
-extern void get_msg_file(void);
-extern void loadfont(void);
-extern void loadkeys(void);
+extern void get_msg_file(char *);
+extern void loadfont(char *);
+extern void loadkeys(char *);
 
 extern char syslinux_banner[];
 extern char copyright_str[];
@@ -1120,7 +1120,6 @@ do_include:
 	 * display/font/kbdmap are rather similar, open a file then do sth
 	 */
 	else if (looking_at(p, "display")) {
-		com32sys_t reg;
 		char *filename, *dst = KernelName;
 		size_t len = FILENAME_MAX - 1;
 
@@ -1130,17 +1129,9 @@ do_include:
 			*dst++ = *filename++;
 		*dst = '\0';
 
-		memset(&reg, 0, sizeof(reg));
-		reg.edi.w[0] = OFFS_WRT(KernelName, 0);
-		call16(core_open, &reg, &reg);
-		if (!(reg.eflags.l & EFLAGS_ZF))
-			call16(get_msg_file, &reg, NULL);
-		else
-			printf("File not found\n");
-
+		get_msg_file(KernelName);
 		refstr_put(filename);
 	} else if (looking_at(p, "font")) {
-		com32sys_t reg;
 		char *filename, *dst = KernelName;
 		size_t len = FILENAME_MAX - 1;
 
@@ -1150,14 +1141,7 @@ do_include:
 			*dst++ = *filename++;
 		*dst = '\0';
 
-		memset(&reg, 0, sizeof(reg));
-		reg.edi.w[0] = OFFS_WRT(KernelName, 0);
-		call16(core_open, &reg, &reg);
-		if (!(reg.eflags.l & EFLAGS_ZF))
-			call16(loadfont, &reg, NULL);
-		else
-			printf("File not found\n");
-
+		loadfont(KernelName);
 		refstr_put(filename);
 	} else if (looking_at(p, "kbdmap")) {
 		com32sys_t reg;
@@ -1170,14 +1154,7 @@ do_include:
 			*dst++ = *filename++;
 		*dst = '\0';
 
-		memset(&reg, 0, sizeof(reg));
-		reg.edi.w[0] = OFFS_WRT(KernelName, 0);
-		call16(core_open, &reg, &reg);
-		if (!(reg.eflags.l & EFLAGS_ZF))
-			call16(loadkeys, &reg, NULL);
-		else
-			printf("File not found\n");
-
+		loadkeys(KernelName);
 		refstr_put(filename);
 	}
 	/*
@@ -1279,8 +1256,7 @@ do_include:
 		/*
 		 * Begin code to actually set up the serial port
 		 */
-		memset(&ireg, 0, sizeof(ireg));
-		call16(sirq_cleanup_nowipe, &ireg, NULL);
+		sirq_cleanup_nowipe();
 
 		outb(0x83, port + 3); /* Enable DLAB */
 		io_delay();
@@ -1319,17 +1295,14 @@ do_include:
 
 		/* Enable interrupts if requested */
 		if (FlowOutput & 0x8)
-			call16(sirq_install, &ireg, NULL);
+			sirq_install();
 
 		/* Show some life */
 		if (SerialNotice != 0) {
 			SerialNotice = 0;
 
-			ireg.esi.w[0] = syslinux_banner;
-			call16(write_serial_str, &ireg, NULL);
-
-			ireg.esi.w[0] = copyright_str;
-			call16(write_serial_str, &ireg, NULL);
+			write_serial_str(syslinux_banner);
+			write_serial_str(copyright_str);
 		}
 	} else if (looking_at(p, "say")) {
 		printf("%s\n", p + 4);
diff --git a/core/abort.inc b/core/abort.inc
deleted file mode 100644
index 9b18136..0000000
--- a/core/abort.inc
+++ /dev/null
@@ -1,84 +0,0 @@
-; -----------------------------------------------------------------------
-;
-;   Copyright 2005-2009 H. Peter Anvin - All Rights Reserved
-;   Copyright 2009 Intel Corporation; author: H. Peter Anvin
-;
-;   This program is free software; you can redistribute it and/or modify
-;   it under the terms of the GNU General Public License as published by
-;   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
-;   Boston MA 02111-1307, USA; either version 2 of the License, or
-;   (at your option) any later version; incorporated herein by reference.
-;
-; -----------------------------------------------------------------------
-
-;
-; abort.inc
-;
-; Code to terminate a kernel load
-;
-
-		section .text16
-
-;
-; dot_pause: same as abort_check, except prints a dot, too
-;            assumes CS == DS
-;
-dot_pause:
-		push si
-		mov si,dot_msg
-		call writestr_qchk
-		pop si
-		; fall through
-
-;
-; abort_check: let the user abort with <ESC> or <Ctrl-C>
-;
-abort_check:
-		call reset_idle			; Not idle despite pollchar
-		call pollchar
-		jz .ret1
-		pusha
-		call getchar
-		cmp al,27			; <ESC>
-		je .kill
-		cmp al,3			; <Ctrl-C>
-		je .kill
-.ret2:		popa
-.ret1:		ret
-
-.kill:		mov si,aborted_msg
-		mov bx,enter_command
-		jmp abort_load_chain
-
-;
-; abort_load: Called by various routines which wants to print a fatal
-;             error message and return to the command prompt.  Since this
-;             may happen at just about any stage of the boot process, assume
-;             our state is messed up, and just reset the segment registers
-;             and the stack forcibly.
-;
-;             SI    = offset (in _text) of error message to print
-;	      BX    = future entry point (abort_load_chain)
-;
-abort_load:
-		mov bx,error_or_command
-abort_load_chain:
-		RESET_STACK_AND_SEGS AX
-                call writestr                  ; Expects SI -> error msg
-
-		; Return to the command prompt
-		jmp bx
-
-;
-; error_or_command: Execute ONERROR if appropriate, otherwise enter_command
-;
-error_or_command:
-		mov cx,[OnerrorLen]
-		and cx,cx
-		jnz on_error
-		jmp enter_command
-
-		section .data16
-aborted_msg	db ' aborted.', CR, LF, 0
-
-		section .text16
diff --git a/core/cleanup.c b/core/cleanup.c
new file mode 100644
index 0000000..7bf1df2
--- /dev/null
+++ b/core/cleanup.c
@@ -0,0 +1,46 @@
+/* -----------------------------------------------------------------------
+ *
+ *   Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * -----------------------------------------------------------------------
+ */
+#include <com32.h>
+#include <core.h>
+
+extern void timer_cleanup(void);
+extern void comboot_cleanup_api(void);
+
+/*
+ * cleanup.c
+ *
+ * Some final tidying before jumping to a kernel or bootsector
+ */
+
+/*
+ * cleanup_hardware:
+ *
+ *	Shut down anything transient.
+ */
+void cleanup_hardware(void)
+{
+	/*
+	 * TODO
+	 *
+	 * Linux wants the floppy motor shut off before starting the
+	 * kernel, at least bootsect.S seems to imply so.  If we don't
+	 * load the floppy driver, this is *definitely* so!
+	 */
+	__intcall(0x13, &zero_regs, NULL);
+
+	call16(comboot_cleanup_api, &zero_regs, NULL);
+	call16(timer_cleanup, &zero_regs, NULL);
+
+	/* If we enabled serial port interrupts, clean them up now */
+	sirq_cleanup();
+}
diff --git a/core/cleanup.inc b/core/cleanup.inc
deleted file mode 100644
index 300584c..0000000
--- a/core/cleanup.inc
+++ /dev/null
@@ -1,60 +0,0 @@
-;; -----------------------------------------------------------------------
-;;
-;;   Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
-;;
-;;   This program is free software; you can redistribute it and/or modify
-;;   it under the terms of the GNU General Public License as published by
-;;   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
-;;   Boston MA 02111-1307, USA; either version 2 of the License, or
-;;   (at your option) any later version; incorporated herein by reference.
-;;
-;; -----------------------------------------------------------------------
-
-;;
-;; cleanup.inc
-;;
-;; Some final tidying before jumping to a kernel or bootsector
-;;
-
-		section .text16
-;
-; cleanup_hardware:
-;
-;	Shut down anything transient.  *No segment assumptions*.
-;	Preserves all registers.
-;
-cleanup_hardware:
-		pushad
-;
-; Linux wants the floppy motor shut off before starting the kernel,
-; at least bootsect.S seems to imply so.  If we don't load the floppy
-; driver, this is *definitely* so!
-;
-		xor ax,ax
-		xor dx,dx
-		int 13h
-
-%if 0		; This bug report has not been substantiated!
-; Vmware crashes if we scroll in the decompressor!  Try to detect vmware
-; and if it is Vmware, clear the screen...
-		mov eax,'VMXh'
-		xor ebx, ebx
-		mov ecx, 10		; Get version
-		mov dx, 'VX'
-		in eax, dx
-		cmp ebx, 'VMXh'
-		jne .no_vmware
-
-		mov ax,0x0003		; Set mode (clear screen/home cursor)
-		int 10h
-.no_vmware:
-%endif
-
-		call comboot_cleanup_api
-
-		call timer_cleanup
-
-		popad
-
-		; If we enabled serial port interrupts, clean them up now
-		jmp sirq_cleanup
diff --git a/core/comboot.inc b/core/comboot.inc
index b0e118a..880f5db 100644
--- a/core/comboot.inc
+++ b/core/comboot.inc
@@ -173,6 +173,7 @@ comboot_setup_api:
 ; Restore the original state of the COMBOOT API vectors, and free
 ; any low memory allocated by the comboot module.
 ;
+		global comboot_cleanup_api
 comboot_cleanup_api:
 		pusha
 		mov si,DOSSaveVectors
@@ -238,7 +239,7 @@ comboot_int21:	sti
 		mov es,bp
 		mov bp,sp			; Set up stack frame
 
-		call adjust_screen		; The COMBOOT program might have changed the screen
+		call _adjust_screen		; The COMBOOT program might have changed the screen
 
 		mov cx,int21_count
 		mov si,int21_table
@@ -309,7 +310,7 @@ comboot_exit_msg:
 		pop bx			; Return address
 		RESET_STACK_AND_SEGS si	; Contains sti, cld
 		pm_call comboot_cleanup_lowmem
-		call adjust_screen	; The COMBOOT program might have changed the screen
+		call _adjust_screen	; The COMBOOT program might have changed the screen
 		jcxz .nomsg
 		mov si,KernelName
 		call writestr
@@ -425,7 +426,7 @@ comboot_int22:
 		mov es,bp
 		mov bp,sp			; Set up stack frame
 
-		call adjust_screen		; The COMBOOT program might have changed the screen
+		call _adjust_screen		; The COMBOOT program might have changed the screen
 
 		cmp ax,int22_count
 		jb .ok
@@ -807,7 +808,7 @@ comapi_usingvga:
 		mov [GXPixRows],dx
 		test al,08h
 		jnz .notext
-		call adjust_screen
+		call _adjust_screen
 .notext:
 		clc
 		ret
@@ -1002,6 +1003,11 @@ feature_flags_len equ ($-feature_flags)
 err_notdos	db ': attempted DOS system call INT ',0
 err_comlarge	db 'COMBOOT image too large.', CR, LF, 0
 
+		global VGAFontSize, UserFont
+		alignz 2
+VGAFontSize	dw 16			; Defaults to 16 byte font
+UserFont	db 0			; Using a user-specified font
+
 		section .bss16
 		alignb 4
 DOSErrTramp	resd	33		; Error trampolines
diff --git a/core/common.inc b/core/common.inc
index 0b507ce..1a6840e 100644
--- a/core/common.inc
+++ b/core/common.inc
@@ -5,15 +5,12 @@
 ;
 
 %include "getc.inc"		; getc et al
-%include "conio.inc"		; Console I/O
 %include "configinit.inc"	; Initialize configuration
 %include "parseconfig.inc"	; High-level config file handling
 %include "parsecmd.inc"		; Low-level config file handling
 %include "pm.inc"		; Protected mode
 %include "bcopy32.inc"		; 32-bit bcopy
 %include "loadhigh.inc"		; Load a file into high memory
-%include "font.inc"		; VGA font stuff
-%include "graphics.inc"		; VGA graphics
 %include "strcpy.inc"           ; strcpy()
 %include "idle.inc"		; Idle handling
 %include "adv.inc"		; Auxillary Data Vector
diff --git a/core/conio.c b/core/conio.c
new file mode 100644
index 0000000..ddccbdb
--- /dev/null
+++ b/core/conio.c
@@ -0,0 +1,600 @@
+/*
+ * -----------------------------------------------------------------------
+ *
+ *   Copyright 1994-2008 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * -----------------------------------------------------------------------
+ *
+ *
+ * conio.c
+ *
+ * Console I/O code, except:
+ *   writechr, writestr_early	- module-dependent
+ *   writestr, crlf		- writestr.inc
+ *   writehex*			- writehex.inc
+ */
+#include <sys/io.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <fs.h>
+#include "bios.h"
+#include <com32.h>
+#include <sys/cpu.h>
+
+union screen _cursor;
+union screen _screensize;
+
+/*
+ * Serial console stuff.
+ */
+uint16_t SerialPort = 0;	    /* Serial port base (or 0 for no serial port) */
+uint16_t BaudDivisor = 115200/9600; /* Baud rate divisor */
+uint8_t FlowOutput = 0;		    /* Output to assert for serial flow */
+uint8_t FlowInput = 0;		    /* Input bits for serial flow */
+uint8_t FlowIgnore = 0;		    /* Ignore input unless these bits set */
+
+uint8_t ScrollAttribute = 0x07; /* Grey on white (normal text color) */
+uint16_t DisplayCon = 0x01;	/* Display console enabled */
+static uint8_t TextAttribute;	/* Text attribute for message file */
+static uint8_t DisplayMask;	/* Display modes mask */
+
+/* Routine to interpret next print char */
+static void (*NextCharJump)(char);
+
+void msg_initvars(void);
+static void msg_setfg(char data);
+static void msg_putchar(char ch);
+
+uint8_t KbdMap[256];	/* Keyboard map */
+
+/*
+ * loadkeys:	Load a LILO-style keymap
+ *
+ * Returns 0 on success, or -1 on error.
+ */
+int loadkeys(char *filename)
+{
+	FILE *f;
+
+	f = fopen(filename, "r");
+	if (!f)
+		return -1;
+
+	fread(KbdMap, 1, sizeof(KbdMap), f);
+
+	fclose(f);
+	return 0;
+}
+
+/*
+ *
+ * get_msg_file: Load a text file and write its contents to the screen,
+ *               interpreting color codes.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+int get_msg_file(char *filename)
+{
+	FILE *f;
+	char ch;
+
+	f = fopen(filename, "r");
+	if (!f)
+		return -1;
+
+	TextAttribute = 0x7;	/* Default grey on white */
+	DisplayMask = 0x7;	/* Display text in all modes */
+	msg_initvars();
+
+	/*
+	 * Read the text file a byte at a time and interpret that
+	 * byte.
+	 */
+	while ((ch = getc(f)) != EOF) {
+		/* DOS EOF? */
+		if (ch == 0x1A)
+			break;
+
+		/*
+		 * 01h = text mode
+		 * 02h = graphics mode
+		 */
+		UsingVGA &= 0x1;
+		UsingVGA += 1;
+
+		NextCharJump(ch);	/* Do what shall be done */
+	}
+
+	fclose(f);
+	return 0;
+}
+
+static inline void msg_beep(void)
+{
+	com32sys_t ireg, oreg;
+
+	ireg.eax.w[0] = 0x0E07;	/* Beep */
+	ireg.ebx.w[0] = 0x0000;
+	__intcall(0x10, &ireg, &oreg);
+}
+
+/*
+ * write_serial: If serial output is enabled, write character on
+ * serial port.
+ */
+void write_serial(char data)
+{
+	if (!SerialPort)
+		return;
+
+	while (1) {
+		char ch;
+
+		ch = inb(SerialPort + 5); /* LSR */
+
+		/* Wait for space in transmit register */
+		if (!(ch & 0x20))
+			continue;
+
+		/* Wait for input flow control */
+		ch = inb(SerialPort + 6);
+		ch &= FlowInput;
+		if (ch != FlowInput)
+			continue;
+
+		break;
+	}
+
+	outb(data, SerialPort);	/* Send data */
+	io_delay();
+}
+
+void pm_write_serial(com32sys_t *regs)
+{
+	write_serial(regs->eax.b[0]);
+}
+
+void pm_serialcfg(com32sys_t *regs)
+{
+	uint8_t al, ah;
+
+	regs->eax.w[0] = SerialPort;
+	regs->ecx.w[0] = BaudDivisor;
+
+	al = FlowOutput;
+	ah = FlowInput;
+
+	al |= ah;
+	ah = FlowIgnore;
+	ah >>= 4;
+
+	if (!DisplayCon)
+		ah |= 0x80;
+
+	regs->ebx.w[0] = al | (ah << 8);
+}
+
+static void write_serial_displaymask(char data)
+{
+	if (DisplayMask & 0x4)
+		write_serial(data);
+}
+
+/*
+ * write_serial_str: write_serial for strings
+ */
+void write_serial_str(char *data)
+{
+	char ch;
+
+	while ((ch = *data++))
+		write_serial(ch);
+}
+
+/*
+ * write_serial_str_displaymask: d:o, but ignore if DisplayMask & 04h == 0
+ */
+static void write_serial_str_displaymask(char *data)
+{
+	if (DisplayMask & 0x4)
+		write_serial_str(data);
+}
+
+/*
+ * pollchar: check if we have an input character pending
+ *
+ * Returns 1 if character pending.
+ */
+int pollchar(void)
+{
+	com32sys_t ireg, oreg;
+	uint8_t data = 0;
+
+	memset(&ireg, 0, sizeof(ireg));
+
+	ireg.eax.b[1] = 0x11;	/* Poll keyboard */
+	__intcall(0x16, &ireg, &oreg);
+
+	if (!(oreg.eflags.l & EFLAGS_ZF))
+		return 1;
+
+	if (SerialPort) {
+		cli();
+
+		/* Already-queued input? */
+		if (SerialTail == SerialHead) {
+			/* LSR */
+			data = inb(SerialPort + 5) & 1;
+			if (data) {
+				/* MSR */
+				data = inb(SerialPort + 6);
+
+				/* Required status bits */
+				if (data) {
+					data &= FlowIgnore;
+					if (data != FlowIgnore)
+						data = 0;
+					else
+						data = 1;
+				}
+			}
+		}
+		sti();
+	}
+
+	return data;
+}
+
+int pm_pollchar(com32sys_t *regs)
+{
+	if (pollchar())
+		regs->eflags.l &= ~EFLAGS_ZF;
+	else
+		regs->eflags.l |= EFLAGS_ZF;
+}
+
+extern void do_idle(void);
+
+/*
+ * getchar: Read a character from keyboard or serial port
+ */
+char getchar(void)
+{
+	com32sys_t ireg, oreg;
+	unsigned char data;
+
+	memset(&ireg, 0, sizeof(ireg));
+	memset(&oreg, 0, sizeof(oreg));
+	while (1) {
+		call16(do_idle, &zero_regs, NULL);
+
+		ireg.eax.b[1] = 0x11;	/* Poll keyboard */
+		__intcall(0x16, &ireg, &oreg);
+
+		if (oreg.eflags.l & EFLAGS_ZF) {
+			if (!SerialPort)
+				continue;
+
+			cli();
+			if (SerialTail != SerialHead) {
+				/* serial queued */
+				sti(); /* We already know we'll consume data */
+				data = *SerialTail++;
+
+				SerialTail = (unsigned char *)((unsigned long)SerialTail & (serial_buf_size - 1));
+			} else {
+				/* LSR */
+				data = inb(SerialPort + 5) & 1;
+				if (!data) {
+					sti();
+					continue;
+				}
+				data = inb(SerialPort + 6);
+				data &= FlowIgnore;
+				if (data != FlowIgnore) {
+					sti();
+					continue;
+				}
+
+				data = inb(SerialPort);
+				sti();
+				break;
+			}
+		} else {
+			/* Keyboard input? */
+			ireg.eax.b[1] = 0x10; /* Get keyboard input */
+			__intcall(0x16, &ireg, &oreg);
+
+			data = oreg.eax.b[0];
+			if (data == 0xE0)
+				data = 0;
+
+			if (data) {
+				/* Convert character sets */
+				data = KbdMap[data];
+			}
+		}
+
+		break;
+	}
+
+	reset_idle();		/* Character received */
+	return data;
+}
+
+void pm_getchar(com32sys_t *regs)
+{
+	regs->eax.b[0] = getchar();
+}
+
+static void msg_setbg(char data)
+{
+	if (unhexchar(&data) == 0) {
+		data <<= 4;
+		if (DisplayMask & UsingVGA)
+			TextAttribute = data;
+
+		NextCharJump = msg_setfg;
+	} else {
+		TextAttribute = 0x7;	/* Default attribute */
+		NextCharJump = msg_putchar;
+	}
+}
+
+static void msg_setfg(char data)
+{
+	if (unhexchar(&data) == 0) {
+		if (DisplayMask & UsingVGA) {
+			/* setbg set foreground to 0 */
+			TextAttribute |= data;
+		}
+	} else
+		TextAttribute = 0x7;	/* Default attribute */
+
+	NextCharJump = msg_putchar;
+}
+
+static inline void msg_ctrl_o(void)
+{
+	NextCharJump = msg_setbg;
+}
+
+static void msg_gotoxy(void)
+{
+	com32sys_t ireg, oreg;
+
+	memset(&ireg, 0, sizeof(ireg));
+
+	ireg.ebx.b[1] = *(uint8_t *)BIOS_page;
+	ireg.edx.w[0] = CursorDX;
+	ireg.eax.b[1] = 0x02;	/* Set cursor position */
+
+	__intcall(0x10, &ireg, &oreg);
+}
+
+static void msg_newline(void)
+{
+	com32sys_t ireg, oreg;
+	char crlf_msg[] = { '\r', '\n', '\0' };
+
+	write_serial_str_displaymask(crlf_msg);
+
+	if (!(DisplayMask & UsingVGA))
+		return;
+
+	CursorCol = 0;
+	if ((CursorRow + 1) <= VidRows)
+		CursorRow++;
+	else {
+		ireg.ecx.w[0] = 0x0;	/* Upper left hand corner */
+		ireg.edx.w[0] = ScreenSize;
+
+		CursorRow = ireg.edx.b[1]; /* New cursor at the bottom */
+
+		ireg.ebx.b[1] = ScrollAttribute;
+		ireg.eax.w[0] = 0x0601; /* Scroll up one line */
+
+		__intcall(0x10, &ireg, &oreg);
+	}
+
+	msg_gotoxy();
+}
+
+static void msg_formfeed(void)
+{
+	char crff_msg[] = { '\r', '\f', '\0' };
+
+	write_serial_str_displaymask(crff_msg);
+
+	if (DisplayMask & UsingVGA) {
+		com32sys_t ireg, oreg;
+
+		memset(&ireg, 0, sizeof(ireg));
+
+		CursorDX = 0x0;	/* Upper left hand corner */
+
+		ireg.edx.w[0] = ScreenSize;
+		ireg.ebx.b[1] = TextAttribute;
+
+		ireg.eax.w[0] = 0x0600; /* Clear screen region */
+		__intcall(0x10, &ireg, &oreg);
+
+		msg_gotoxy();
+	}
+}
+
+static void msg_novga(void)
+{
+	vgaclearmode();
+	msg_initvars();
+}
+
+static void msg_viewimage(void)
+{
+	FILE *f;
+
+	*VGAFilePtr = '\0';	/* Zero-terminate filename */
+
+	mangle_name(VGAFileMBuf, VGAFileBuf);
+	f = fopen(VGAFileMBuf, "r");
+	if (!f) {
+		/* Not there */
+		NextCharJump = msg_putchar;
+		return;
+	}
+
+	vgadisplayfile(f);
+	fclose(f);
+	msg_initvars();
+}
+
+/*
+ * Getting VGA filename
+ */
+static void msg_filename(char data)
+{
+	/* <LF> = end of filename */
+	if (data == 0x0A) {
+		msg_viewimage();
+		return;
+	}
+
+	/* Ignore space/control char */
+	if (data > ' ') {
+		if ((char *)VGAFilePtr < (VGAFileBuf + sizeof(VGAFileBuf)))
+			*VGAFilePtr++ = data;
+	}
+}
+
+static void msg_vga(void)
+{
+	NextCharJump = msg_filename;
+	VGAFilePtr = (uint16_t *)VGAFileBuf;
+}
+
+static void msg_line_wrap(void)
+{
+	if (!(DisplayMask & UsingVGA))
+		return;
+
+	CursorCol = 0;
+	if ((CursorRow + 1) <= VidRows)
+		CursorRow++;
+	else {
+		com32sys_t ireg, oreg;
+
+		memset(&ireg, 0, sizeof(ireg));
+
+		ireg.ecx.w[0] = 0x0;	   /* Upper left hand corner */
+		ireg.edx.w[0] = ScreenSize;
+
+		CursorRow = ireg.edx.b[1]; /* New cursor at the bottom */
+
+		ireg.ebx.b[1] = ScrollAttribute;
+		ireg.eax.w[0] = 0x0601; /* Scroll up one line */
+
+		__intcall(0x10, &ireg, &oreg);
+	}
+
+	msg_gotoxy();
+}
+
+static void msg_normal(char data)
+{
+	com32sys_t ireg, oreg;
+
+	/* Write to serial port */
+	write_serial_displaymask(data);
+
+	if (!(DisplayMask & UsingVGA))
+		return;		/* Not screen */
+
+	if (!(DisplayCon & 0x01))
+		return;
+
+	memset(&ireg, 0, sizeof(ireg));
+
+	ireg.ebx.b[0] = TextAttribute;
+	ireg.ebx.b[1] = *(uint8_t *)BIOS_page;
+	ireg.eax.b[0] = data;
+	ireg.eax.b[1] = 0x09;	/* Write character/attribute */
+	ireg.ecx.w[0] = 1;	/* One character only */
+
+	/* Write to screen */
+	__intcall(0x10, &ireg, &oreg);
+
+	if ((CursorCol + 1) <= VidCols) {
+		CursorCol++;
+		msg_gotoxy();
+	} else
+		msg_line_wrap(); /* Screen wraparound */
+}
+
+static void msg_modectl(char data)
+{
+	data &= 0x07;
+	DisplayMask = data;
+	NextCharJump = msg_putchar;
+}
+
+static void msg_putchar(char ch)
+{
+	/* 10h to 17h are mode controls */
+	if (ch >= 0x10 && ch < 0x18) {
+		msg_modectl(ch);
+		return;
+	}
+
+	switch (ch) {
+	case 0x0F:		/* ^O = color code follows */
+		msg_ctrl_o();
+		break;
+	case 0x0D:		/* Ignore <CR> */
+		break;
+	case 0x0A:		/* <LF> = newline */
+		msg_newline();
+		break;
+	case 0x0C:		/* <FF> = clear screen */
+		msg_formfeed();
+		break;
+	case 0x07:		/* <BEL> = beep */
+		msg_beep();
+		break;
+	case 0x19:		/* <EM> = return to text mode */
+		msg_novga();
+		break;
+	case 0x18:		/* <CAN> = VGA filename follows */
+		msg_vga();
+		break;
+	default:
+		msg_normal(ch);
+		break;
+	}
+}
+
+/*
+ * Subroutine to initialize variables, also needed after loading
+ * graphics file.
+ */
+void msg_initvars(void)
+{
+	com32sys_t ireg, oreg;
+
+	ireg.eax.b[1] = 0x3;	/* Read cursor position */
+	ireg.ebx.b[1] = *(uint8_t *)BIOS_page;
+	__intcall(0x10, &ireg, &oreg);
+
+	CursorDX = oreg.edx.w[0];
+
+	/* Initialize state machine */
+	NextCharJump = msg_putchar;
+}
diff --git a/core/conio.inc b/core/conio.inc
deleted file mode 100644
index ec2aa2a..0000000
--- a/core/conio.inc
+++ /dev/null
@@ -1,435 +0,0 @@
-;; -----------------------------------------------------------------------
-;;
-;;   Copyright 1994-2008 H. Peter Anvin - All Rights Reserved
-;;   Copyright 2009 Intel Corporation; author: H. Peter Anvin
-;;
-;;   This program is free software; you can redistribute it and/or modify
-;;   it under the terms of the GNU General Public License as published by
-;;   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
-;;   Boston MA 02111-1307, USA; either version 2 of the License, or
-;;   (at your option) any later version; incorporated herein by reference.
-;;
-;; -----------------------------------------------------------------------
-
-;;
-;; conio.inc
-;;
-;; Console I/O code, except:
-;;   writechr, writestr_early	- module-dependent
-;;   writestr, crlf		- writestr.inc
-;;   writehex*			- writehex.inc
-;;
-
-;
-; loadkeys:	Load a LILO-style keymap; file is open on the top of the
-;		getc stack.
-;
-		section .text16
-
-		global loadkeys
-loadkeys:
-		mov cx,256
-		mov di,trackbuf
-		call readc
-		jc .done				; EOF already?
-
-		; Make sure we are at EOF now...
-		call getc
-		jnc .done			; We should be at EOF now!
-
-		; It was okay, we can now move it into the KbdMap
-		mov si,trackbuf
-		mov di,KbdMap
-		mov cx,256 >> 2
-		rep movsd
-
-.done:
-		call close
-		ret
-
-;
-; get_msg_file: Load a text file and write its contents to the screen,
-;               interpreting color codes.  Call with the file already
-;		on the top of the open/getc stack.
-;
-;		Assumes CS == DS == ES.
-;
-		global get_msg_file
-get_msg_file:
-                mov byte [TextAttribute],07h	; Default grey on white
-		mov byte [DisplayMask],07h	; Display text in all modes
-		call msg_initvars
-
-print_msg_file:
-.getc:
-		call getc
-		jc .done
-                cmp al,1Ah                      ; DOS EOF?
-		je .done
-		movzx cx,byte [UsingVGA]
-		and cl,01h
-		inc cx				; CL <- 01h = text mode,
-						;       02h = graphics mode
-                call [NextCharJump]		; Do what shall be done
-		jmp .getc
-.done:
-		jmp close			; Tailcall!
-
-msg_putchar:                                    ; Normal character
-                cmp al,0Fh                      ; ^O = color code follows
-                je msg_ctrl_o
-                cmp al,0Dh                      ; Ignore <CR>
-                je msg_ignore
-                cmp al,0Ah                      ; <LF> = newline
-                je msg_newline
-                cmp al,0Ch                      ; <FF> = clear screen
-                je msg_formfeed
-		cmp al,07h			; <BEL> = beep
-		je msg_beep
-		cmp al,19h			; <EM> = return to text mode
-		je msg_novga
-		cmp al,18h			; <CAN> = VGA filename follows
-		je msg_vga
-		jnb .not_modectl
-		cmp al,10h			; 10h to 17h are mode controls
-		jae msg_modectl
-.not_modectl:
-
-msg_normal:	call write_serial_displaymask	; Write to serial port
-		test [DisplayMask],cl
-		jz msg_ignore			; Not screen
-		test byte [DisplayCon],01h
-		jz msg_ignore
-                mov bl,[TextAttribute]
-		mov bh,[BIOS_page]
-                mov ah,09h                      ; Write character/attribute
-                mov cx,1                        ; One character only
-                int 10h                         ; Write to screen
-                mov al,[CursorCol]
-                inc ax
-                cmp al,[VidCols]
-                ja msg_line_wrap		; Screen wraparound
-                mov [CursorCol],al
-
-msg_gotoxy:     mov bh,[BIOS_page]
-                mov dx,[CursorDX]
-                mov ah,02h                      ; Set cursor position
-                int 10h
-msg_ignore:     ret
-
-msg_beep:	mov ax,0E07h			; Beep
-		xor bx,bx
-		int 10h
-		ret
-
-msg_ctrl_o:                                     ; ^O = color code follows
-                mov word [NextCharJump],msg_setbg
-                ret
-msg_newline:                                    ; Newline char or end of line
-		mov si,crlf_msg
-		call write_serial_str_displaymask
-msg_line_wrap:					; Screen wraparound
-		test [DisplayMask],cl
-		jz msg_ignore
-                mov byte [CursorCol],0
-                mov al,[CursorRow]
-                inc ax
-                cmp al,[VidRows]
-                ja msg_scroll
-                mov [CursorRow],al
-                jmp short msg_gotoxy
-msg_scroll:     xor cx,cx                       ; Upper left hand corner
-                mov dx,[ScreenSize]
-                mov [CursorRow],dh		; New cursor at the bottom
-                mov bh,[ScrollAttribute]
-                mov ax,0601h                    ; Scroll up one line
-                int 10h
-                jmp short msg_gotoxy
-msg_formfeed:                                   ; Form feed character
-		mov si,crff_msg
-		call write_serial_str_displaymask
-		test [DisplayMask],cl
-		jz msg_ignore
-                xor cx,cx
-                mov [CursorDX],cx		; Upper lefthand corner
-                mov dx,[ScreenSize]
-                mov bh,[TextAttribute]
-                mov ax,0600h                    ; Clear screen region
-                int 10h
-                jmp msg_gotoxy
-msg_setbg:                                      ; Color background character
-                call unhexchar
-                jc msg_color_bad
-                shl al,4
-		test [DisplayMask],cl
-		jz .dontset
-                mov [TextAttribute],al
-.dontset:
-                mov word [NextCharJump],msg_setfg
-                ret
-msg_setfg:                                      ; Color foreground character
-                call unhexchar
-                jc msg_color_bad
-		test [DisplayMask],cl
-		jz .dontset
-                or [TextAttribute],al		; setbg set foreground to 0
-.dontset:
-		jmp short msg_putcharnext
-msg_vga:
-		mov word [NextCharJump],msg_filename
-		mov di, VGAFileBuf
-		jmp short msg_setvgafileptr
-
-msg_color_bad:
-                mov byte [TextAttribute],07h	; Default attribute
-msg_putcharnext:
-                mov word [NextCharJump],msg_putchar
-		ret
-
-msg_filename:					; Getting VGA filename
-		cmp al,0Ah			; <LF> = end of filename
-		je msg_viewimage
-		cmp al,' '
-		jbe msg_ret			; Ignore space/control char
-		mov di,[VGAFilePtr]
-		cmp di,VGAFileBufEnd
-		jnb msg_ret
-		mov [di],al			; Can't use stosb (DS:)
-		inc di
-msg_setvgafileptr:
-		mov [VGAFilePtr],di
-msg_ret:	ret
-
-msg_novga:
-		call vgaclearmode
-		jmp short msg_initvars
-
-msg_viewimage:
-		mov si,[VGAFilePtr]
-		mov byte [si],0			; Zero-terminate filename
-		mov si,VGAFileBuf
-		mov di,VGAFileMBuf
-		pm_call pm_mangle_name
-		call core_open
-		jz msg_putcharnext		; Not there
-		call vgadisplayfile
-		; Fall through
-
-		; Subroutine to initialize variables, also needed
-		; after loading a graphics file
-msg_initvars:
-                pusha
-                mov bh,[BIOS_page]
-                mov ah,03h                      ; Read cursor position
-                int 10h
-                mov [CursorDX],dx
-                popa
-		jmp short msg_putcharnext	; Initialize state machine
-
-msg_modectl:
-		and al,07h
-		mov [DisplayMask],al
-		jmp short msg_putcharnext
-
-;
-; write_serial:	If serial output is enabled, write character on serial port
-; write_serial_displaymask: d:o, but ignore if DisplayMask & 04h == 0
-;
-write_serial_displaymask:
-		test byte [DisplayMask], 04h
-		jz write_serial.end
-write_serial:
-		pushfd
-		pushad
-		mov bx,[SerialPort]
-		and bx,bx
-		je .noserial
-		push ax
-		mov ah,[FlowInput]
-.waitspace:
-		; Wait for space in transmit register
-		lea dx,[bx+5]			; DX -> LSR
-		in al,dx
-		test al,20h
-		jz .waitspace
-
-		; Wait for input flow control
-		inc dx				; DX -> MSR
-		in al,dx
-		and al,ah
-		cmp al,ah
-		jne .waitspace
-.no_flow:
-
-		xchg dx,bx			; DX -> THR
-		pop ax
-		slow_out dx,al			; Send data
-.noserial:	popad
-		popfd
-.end:		ret
-
-;
-; write_serial_str: write_serial for strings
-; write_serial_str_displaymask: d:o, but ignore if DisplayMask & 04h == 0
-;
-write_serial_str_displaymask:
-		test byte [DisplayMask], 04h
-		jz write_serial_str.end
-
-		global write_serial_str
-write_serial_str:
-.loop		lodsb
-		and al,al
-		jz .end
-		call write_serial
-		jmp short .loop
-.end:		ret
-
-;
-; pollchar: check if we have an input character pending (ZF = 0)
-;
-pollchar:
-		pushad
-		mov ah,11h		; Poll keyboard
-		int 16h
-		jnz .done		; Keyboard response
-		mov dx,[SerialPort]
-		and dx,dx
-		jz .done		; No serial port -> no input
-		mov ax,[SerialTail]	; Already-queued input?
-		cli
-		cmp ax,[SerialHead]
-		jne .done_sti		; If so, return ZF = 0
-		add dx,5		; DX -> LSR
-		in al,dx
-		test al,1		; ZF = 0 if data pending
-		jz .done_sti
-		inc dx			; DX -> MSR
-		mov ah,[FlowIgnore]	; Required status bits
-		in al,dx
-		and al,ah
-		cmp al,ah
-		setne al
-		dec al			; Set ZF = 0 if equal
-.done_sti:	sti
-.done:		popad
-		ret
-
-;
-; getchar: Read a character from keyboard or serial port
-;
-getchar.sti_again:
-		sti
-getchar:
-.again:
-		call do_idle
-		mov ah,11h		; Poll keyboard
-		int 16h
-		jnz .kbd		; Keyboard input?
-		mov bx,[SerialPort]
-		and bx,bx
-		jz .again
-		mov ax,[SerialTail]
-		cli
-		cmp ax,[SerialHead]
-		jne .serial_queued
-		lea dx,[bx+5]		; DX -> LSR
-		in al,dx
-		test al,1
-		jz .sti_again
-		inc dx			; DX -> MSR
-		mov ah,[FlowIgnore]
-		in al,dx
-		and al,ah
-		cmp al,ah
-		jne .sti_again
-.serial:	xor ah,ah		; Avoid confusion
-		mov dx,bx		; Data port
-		in al,dx		; Read data
-		sti
-		jmp .done
-.serial_queued:
-		sti			; We already know we'll consume data
-		xchg bx,ax
-		push ds
-		mov ax,aux_seg + (aux.serial >> 4)
-		mov ds,ax
-		mov al,[bx]
-		pop ds
-		inc bx
-		and bx,serial_buf_size-1
-		mov [SerialTail],bx
-		jmp .done
-
-.kbd:		mov ah,10h		; Get keyboard input
-		int 16h
-		cmp al,0E0h
-		jnz .not_ext
-		xor al,al
-.not_ext:
-		and al,al
-		jz .func_key
-		mov bx,KbdMap		; Convert character sets
-		xlatb
-.func_key:
-.done:
-		jmp reset_idle		; Character received
-
-%ifdef DEBUG_TRACERS
-;
-; debug hack to print a character with minimal code impact
-;
-debug_tracer:	pushad
-		pushfd
-		mov bp,sp
-		mov bx,[bp+9*4]		; Get return address
-		mov al,[cs:bx]		; Get data byte
-		inc word [bp+9*4]	; Return to after data byte
-		call writechr
-		popfd
-		popad
-		ret
-%endif	; DEBUG_TRACERS
-
-		section .data16
-%if IS_ISOLINUX == 0			; Defined elsewhere for ISOLINUX
-crlf_msg	db CR, LF
-null_msg	db 0
-%endif
-crff_msg	db CR, FF, 0
-
-		section .config
-		; This is a word to pc_setint16 can set it
-DisplayCon	dw 01h			; Console display enabled
-
-ScrollAttribute	db 07h			; Grey on white (normal text color)
-
-		section .bss16
-		alignb 2
-NextCharJump    resw 1			; Routine to interpret next print char
-CursorDX        equ $
-CursorCol       resb 1			; Cursor column for message file
-CursorRow       resb 1			; Cursor row for message file
-ScreenSize      equ $
-VidCols         resb 1			; Columns on screen-1
-VidRows         resb 1			; Rows on screen-1
-
-; Serial console stuff; don't put this in .config becasue we don't want
-; loading a new config file to undo this setting.
-		section .data16
-		alignz 4
-		global SerialPort, BaudDivisor, FlowIgnore, FlowInput, FlowOutput
-SerialPort	dw 0			; Serial port base (or 0 for no serial port)
-BaudDivisor	dw 115200/9600		; Baud rate divisor
-FlowControl	equ $
-FlowOutput	db 0			; Outputs to assert for serial flow
-FlowInput	db 0			; Input bits for serial flow
-FlowIgnore	db 0			; Ignore input unless these bits set
-FlowDummy	db 0			; Unused
-
-		section .bss16
-TextAttribute   resb 1			; Text attribute for message file
-DisplayMask	resb 1			; Display modes mask
-
-		section .text16
-%include "serirq.inc"
diff --git a/core/diskfs.inc b/core/diskfs.inc
index 2684328..5a029d3 100644
--- a/core/diskfs.inc
+++ b/core/diskfs.inc
@@ -115,9 +115,7 @@ kaboom2:
 ; -----------------------------------------------------------------------------
 
 %include "common.inc"		; Universal modules
-%include "plaincon.inc"		; writechr
 %include "writestr.inc"		; String output
-%include "writehex.inc"		; Hexadecimal output
 %include "localboot.inc"	; Disk-based local boot
 
 ; -----------------------------------------------------------------------------
diff --git a/core/extern.inc b/core/extern.inc
index 90599f2..dea6052 100644
--- a/core/extern.inc
+++ b/core/extern.inc
@@ -51,4 +51,25 @@
 	extern unload_pxe, reset_pxe
 %endif
 
+	; plaincon.c
+	extern pm_writechr
+
+	; cleanup.c
+	extern cleanup_hardware
+
+	; writestr.c
+	extern pm_writestr, crlf
+
+	; writehex.c
+	extern pm_writehex2, pm_writehex4, pm_writehex8
+
+	; graphics.c
+	extern vgaclearmode, vgashowcursor, vgahidecursor
+
+	; conio.c
+	extern pm_pollchar, pm_write_serial, pm_serialcfg
+
+	; font.c
+	extern pm_getchar, pm_adjust_screen, pm_usingvga, pm_userfont
+
 %endif ; EXTERN_INC
diff --git a/core/font.c b/core/font.c
new file mode 100644
index 0000000..b14d3d2
--- /dev/null
+++ b/core/font.c
@@ -0,0 +1,195 @@
+/*
+ * -----------------------------------------------------------------------
+ *
+ *   Copyright 1994-2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * -----------------------------------------------------------------------
+ *
+ *
+ * font.c
+ *
+ * VGA font handling code
+ *
+ */
+
+#include <sys/io.h>
+#include <stdio.h>
+#include <fs.h>
+#include "bios.h"
+#include "core.h"
+
+struct aux {
+	char fontbuf[8192];
+	char serial[serial_buf_size];
+};
+
+#define fontbuf		offsetof(struct aux, fontbuf)
+
+extern uint16_t VGAFontSize;
+extern uint8_t UserFont;
+
+uint16_t GXPixCols = 1;		/* Graphics mode pixel columns */
+uint16_t GXPixRows = 1;		/* Graphics mode pixel rows */
+
+/*
+ * loadfont:	Load a .psf font file and install it onto the VGA console
+ *		(if we're not on a VGA screen then ignore.)
+ *
+ * The .psf font file must alredy be open and getc_file must be set.
+ */
+void loadfont(char *filename)
+{
+	uint16_t height, magic;
+	uint32_t *di, *si;
+	FILE *f;
+	char *p;
+	int i;
+
+	f = fopen(filename, "r");
+	if (!f)
+		return;
+
+	p = trackbuf;
+	/* Read header */
+	for (i = 0; i < 4; i++) {
+		char ch = getc(f);
+		if (ch == EOF)
+			return;
+		*p++ = ch;
+	}
+
+	/* Magic number */
+	magic = *(uint16_t *)trackbuf;
+	if (magic != 0x0436)
+		return;
+
+	/* File mode: font modes 0-5 supported */
+	if (*(trackbuf) > 5)
+		return;
+
+	height = *(trackbuf + 3); /* Height of font */
+
+	/* VGA minimum/maximum */
+	if (height < 2 || height > 32)
+		return;
+
+	/* Load the actual font. Bytes = font height * 256 */
+	p = trackbuf;
+	for (i = 0; i < (height << 8); i++) {
+		char ch = getc(f);
+
+		if (ch == EOF)
+			return;
+		*p++ = ch;
+	}
+
+	/* Copy to font buffer */
+	VGAFontSize = height;
+	di = (uint32_t *)MK_PTR(aux_seg, fontbuf);
+	si = (uint32_t *)trackbuf;
+	for (i = 0; i < (height << 6); i++)
+		*di++ = *si++;
+
+	UserFont = 1;		/* Set font flag */
+	use_font();
+}
+
+/*
+ * use_font:
+ *	This routine activates whatever font happens to be in the
+ *	vgafontbuf, and updates the adjust_screen data.
+ *      Must be called with CS = DS
+ */
+void use_font(void)
+{
+	com32sys_t ireg, oreg;
+	uint8_t bytes = VGAFontSize;
+
+
+	/* Nonstandard mode? */
+	if (UsingVGA & ~0x3)
+		vgaclearmode();
+
+	memset(&ireg, 0, sizeof(ireg));
+
+	ireg.es = aux_seg;
+	ireg.ebp.w[0] = fontbuf; /* ES:BP -> font */
+
+	/* Are we using a user-specified font? */
+	if (UserFont & 0x1) {
+		/* Are we in graphics mode? */
+		if (UsingVGA & 0x1) {
+			uint8_t rows;
+
+			rows = GXPixRows / bytes;
+			VidRows = rows - 1;
+
+			/* Set user character table */
+			ireg.eax.w[0] = 0x1121;
+			ireg.ebx.b[0] = 0;
+			ireg.ecx.b[0] = bytes; /* bytes/character */
+			ireg.edx.b[0] = rows;
+
+			__intcall(0x10, &ireg, &oreg);
+
+			/* 8 pixels/character */
+			VidCols = ((GXPixCols >> 3) - 1);
+
+			/* No need to call adjust_screen */
+			return;
+		} else {
+			ireg.eax.w[0] = 0x1110;	/* Load into VGA RAM */
+			ireg.ebx.b[0] = 0;
+			ireg.ebx.b[1] = bytes; /* bytes/character */
+			ireg.ecx.w[0] = 256;
+			ireg.edx.w[0] = 0;
+
+			__intcall(0x10, &ireg, &oreg);
+
+			ireg.ebx.b[0] = 0;
+			ireg.eax.w[0] = 0x1103; /* Select page 0 */
+			__intcall(0x10, &ireg, NULL);
+		}
+	}
+
+	adjust_screen();
+}
+
+/*
+ * adjust_screen: Set the internal variables associated with the screen size.
+ *		This is a subroutine in case we're loading a custom font.
+ */
+void adjust_screen(void)
+{
+	com32sys_t ireg, oreg;
+	volatile uint8_t *vidrows = BIOS_vidrows;
+	uint8_t rows, cols;
+
+	rows = *vidrows;
+	if (!rows) {
+		/*
+		 * No vidrows in BIOS, assume 25.
+		 * (Remember: vidrows == rows-1)
+		 */
+		rows = 24;
+	}
+
+	VidRows = rows;
+
+	ireg.eax.b[1] = 0x0f;	/* Read video state */
+	__intcall(0x10, &ireg, &oreg);
+	cols = oreg.eax.b[1];
+
+	VidCols = --cols;	/* Store count-1 (same as rows) */
+}
+
+void pm_adjust_screen(com32sys_t *regs)
+{
+	adjust_screen();
+}
diff --git a/core/font.inc b/core/font.inc
deleted file mode 100644
index 9e840e4..0000000
--- a/core/font.inc
+++ /dev/null
@@ -1,153 +0,0 @@
-;; -----------------------------------------------------------------------
-;;
-;;   Copyright 1994-2008 H. Peter Anvin - All Rights Reserved
-;;
-;;   This program is free software; you can redistribute it and/or modify
-;;   it under the terms of the GNU General Public License as published by
-;;   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
-;;   Boston MA 02111-1307, USA; either version 2 of the License, or
-;;   (at your option) any later version; incorporated herein by reference.
-;;
-;; -----------------------------------------------------------------------
-
-;;
-;; font.inc
-;;
-;; VGA font handling code
-;;
-
-		section .text16
-
-;
-; loadfont:	Load a .psf font file and install it onto the VGA console
-;		(if we're not on a VGA screen then ignore.)
-;		The font is on top of the getc stack.
-;
-loadfont.err:	jmp close			; Tailcall the close routine
-
-		global loadfont
-loadfont:
-		mov di,trackbuf
-		mov cx,4
-		call readc			; Read header
-		jc .err
-
-		mov ax,[trackbuf]		; Magic number
-		cmp ax,0436h
-		jne .err
-
-		mov al,[trackbuf+2]		; File mode
-		cmp al,5			; Font modes 0-5 supported
-		ja .err
-
-		xor bx,bx
-		mov bh,[trackbuf+3]		; Height of font
-		cmp bh,2			; VGA minimum
-		jb .err
-		cmp bh,32			; VGA maximum
-		ja .err
-
-		; Load the actual font
-		mov di,trackbuf
-		mov cx,bx			; Bytes = font height * 256
-		call readc
-		jc .err
-
-		call close
-
-		; Copy to font buffer
-		mov si,trackbuf			; Start of font data
-		mov [VGAFontSize],bh
-		push es
-		mov cx,aux_seg
-		mov es,cx
-		mov di,aux.fontbuf
-		mov cx,bx
-		shr cx,2
-		rep movsd
-		pop es
-
-		mov [UserFont], byte 1		; Set font flag
-
-;
-; use_font:
-;	This routine activates whatever font happens to be in the
-;	vgafontbuf, and updates the adjust_screen data.
-;       Must be called with CS = DS
-;
-use_font:
-		test byte [UsingVGA], ~03h	; Nonstandard mode?
-		jz .modeok
-		call vgaclearmode
-
-.modeok:
-		test [UserFont], byte 1		; Are we using a user-specified font?
-		jz adjust_screen		; If not, just do the normal stuff
-
-		push es
-		mov bp,aux_seg
-		mov es,bp
-
-		mov bp,aux.fontbuf		; ES:BP -> font
-		mov bh,[VGAFontSize]
-		xor bl,bl			; Needed by both INT 10h calls
-
-		test byte [UsingVGA], 01h	; Are we in graphics mode?
-		jz .text
-
-.graphics:
-		xor cx,cx
-		mov cl,bh			; CX = bytes/character
-		mov ax,[GXPixRows]
-		div cl				; Compute char rows per screen
-		mov dl,al
-		dec ax
-		mov [VidRows],al
-		mov ax,1121h			; Set user character table
-		int 10h
-		mov ax,[GXPixCols]
-		shr ax,3			; 8 pixels/character
-		dec ax
-		mov [VidCols],al
-		pop es
-		ret				; No need to call adjust_screen
-
-.text:
-		mov cx,256
-		xor dx,dx
-		mov ax,1110h
-		int 10h				; Load into VGA RAM
-		pop es
-
-		xor bl,bl
-		mov ax,1103h			; Select page 0
-		int 10h
-
-;
-; adjust_screen: Set the internal variables associated with the screen size.
-;		This is a subroutine in case we're loading a custom font.
-;
-adjust_screen:
-		pusha
-                mov al,[BIOS_vidrows]
-                and al,al
-                jnz vidrows_ok
-                mov al,24                       ; No vidrows in BIOS, assume 25
-						; (Remember: vidrows == rows-1)
-vidrows_ok:	mov [VidRows],al
-                mov ah,0fh
-                int 10h                         ; Read video state
-                dec ah                          ; Store count-1 (same as rows)
-                mov [VidCols],ah
-		popa
-		ret
-
-		section .data16
-		alignz 2
-VGAFontSize	dw 16			; Defaults to 16 byte font
-UserFont	db 0			; Using a user-specified font
-
-		section .bss16
-		alignb 4
-GXPixCols	resw 1			; Graphics mode pixel columns
-GXPixRows	resw 1			; Graphics mode pixel rows
diff --git a/core/graphics.c b/core/graphics.c
new file mode 100644
index 0000000..7ca20ea
--- /dev/null
+++ b/core/graphics.c
@@ -0,0 +1,382 @@
+/*
+ * -----------------------------------------------------------------------
+ *
+ *   Copyright 1994-2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * -----------------------------------------------------------------------
+ *
+ * -----------------------------------------------------------------------
+ *  VGA splash screen code
+ * -----------------------------------------------------------------------
+ */
+
+#include <stddef.h>
+#include "core.h"
+#include <sys/io.h>
+#include "fs.h"
+#include "bios.h"
+
+uint8_t UsingVGA = 0;
+uint16_t VGAPos;		/* Pointer into VGA memory */
+uint16_t *VGAFilePtr;		/* Pointer into VGAFileBuf */
+
+char VGAFileBuf[VGA_FILE_BUF_SIZE]; /* Unmangled VGA image name */
+char VGAFileMBuf[FILENAME_MAX];	/* Mangled VGA image name */
+
+static uint8_t VGARowBuffer[640 + 80];	/* Decompression buffer */
+static uint8_t VGAPlaneBuffer[(640/8) * 4]; /* Plane buffers */
+
+extern uint16_t GXPixCols;
+extern uint16_t GXPixRows;
+
+/* Maps colors to consecutive DAC registers */
+static uint8_t linear_color[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8,
+				  9, 10, 11, 12, 13, 14, 15, 0 };
+
+static FILE *fd;
+
+typedef struct {
+	uint32_t LSSMagic;	/* Magic number */
+	uint16_t GraphXSize;	/* Width of splash screen file */
+	uint16_t GraphYSize;	/* Height of splash screen file */
+	uint8_t GraphColorMap[3*16];
+} lssheader_t;
+
+static lssheader_t LSSHeader;
+
+#define LSSMagic	LSSHeader.LSSMagic
+#define GraphXSize	LSSHeader.GraphXSize
+#define GraphYSize	LSSHeader.GraphYSize
+
+/*
+ * Enable VGA graphics, if possible. Return 0 on success.
+ */
+static int vgasetmode(void)
+{
+	com32sys_t ireg, oreg;
+
+	if (UsingVGA)
+		return 0;		/* Nothing to do... */
+
+	memset(&ireg, 0, sizeof(ireg));
+	memset(&oreg, 0, sizeof(oreg));
+
+	if (UsingVGA & 0x4) {
+		/*
+		 * We're in VESA mode, which means VGA; use VESA call
+		 * to revert the mode, and then call the conventional
+		 * mode-setting for good measure...
+		 */
+		ireg.eax.w[0] = 0x4F02;
+		ireg.ebx.w[0] = 0x0012;
+		__intcall(0x10, &ireg, &oreg);
+	} else {
+		/* Get video card and monitor */
+		ireg.eax.w[0] = 0x1A00;
+		__intcall(0x10, &ireg, &oreg);
+		oreg.ebx.b[0] -= 7; /* BL=07h and BL=08h OK */
+
+		if (oreg.ebx.b[0] > 1)
+			return -1;
+	}
+
+	/*
+	 * Set mode.
+	 */
+	ireg.eax.w[0] = 0x0012;	/* Set mode = 640x480 VGA 16 colors */
+	__intcall(0x10, &ireg, &oreg);
+
+	ireg.edx.w[0] = (uint16_t)linear_color;
+	ireg.eax.w[0] = 0x1002;	/* Write color registers */
+	__intcall(0x10, &ireg, &oreg);
+
+	UsingVGA = 1;
+
+	/* Set GXPixCols and GXPixRows */
+	GXPixCols = 640+(480 << 16);
+
+	use_font();
+	ScrollAttribute = 0;
+
+	return 0;
+}
+
+static inline char getnybble(void)
+{
+	char data = getc(fd);
+
+	if (data & 0x10) {
+		data &= 0x0F;
+		return data;
+	}
+
+	data = getc(fd);
+	return (data & 0x0F);
+}
+
+/*
+ * rledecode:
+ *	Decode a pixel row in RLE16 format.
+ *
+ * 'in': input (RLE16 encoded) buffer
+ * 'out': output (decoded) buffer
+ * 'count': pixel count
+ */
+static void rledecode(uint8_t *out, size_t count)
+{
+	uint8_t prev_pixel = 0;
+	size_t size = count;
+	uint8_t data;
+	int i;
+
+again:
+	for (i = 0; i < size; i++) {
+
+		data = getnybble();
+		if (data == prev_pixel)
+			break;
+
+		*out++ = data;
+		prev_pixel = data;
+	}
+
+	size -= i;
+	if (!size)
+		return;
+
+	/* Start of run sequence */
+	data = getnybble();
+	if (data == 0) {
+		/* long run */
+		uint8_t hi;
+
+		data = getnybble();
+		hi = getnybble();
+		hi <<= 4;
+		data |= hi;
+		data += 16;
+	}
+
+	/* dorun */
+	for (i = 0; i < data; i++)
+		*out++ = prev_pixel;
+
+	size -= i;
+	if (size)
+		goto again;
+}
+
+/*
+ * packedpixel2vga:
+ *	Convert packed-pixel to VGA bitplanes
+ *
+ * 'in': packed pixel string
+ * 'out': output (four planes)
+ * 'count': pixel count (multiple of 8)
+ */
+static void packedpixel2vga(uint8_t *in, uint8_t *out, size_t count)
+{
+	uint8_t bx, al, dl;
+	int plane, pixel;
+
+	for (plane = 0; plane < 4; plane++) {
+		for (bx = 0; bx < count; bx += 8) {
+			for (pixel = 0; pixel < 8; pixel++) {
+				al = *in++;
+				al >>= plane;
+
+				/*
+				 * VGA is bigendian.  Sigh.
+				 * Left rotate through carry
+				 */
+				dl = dl << 1 | (dl >> (8 - 1));
+			}
+
+			*out++ = dl;
+		}
+	}
+}
+
+/*
+ * outputvga:
+ *	Output four subsequent lines of VGA data
+ *
+ * 'in': four planes @ 640/8=80 bytes
+ * 'out': pointer into VGA memory
+ */
+static void outputvga(uint32_t *in, uint32_t *out)
+{
+	uint8_t val, *addr;
+	int i, j;
+
+	addr = (uint8_t *)0x3C4; /* VGA Sequencer Register select port */
+	val = 2;		 /* Sequencer mask */
+
+	/* Select the sequencer mask */
+	outb(val, (uint16_t)addr);
+
+	addr += 1;		/* VGA Sequencer Register data port */
+	for (i = 1; i <= 8; i *= 2) {
+		/* Select the bit plane to write */
+		outb(i, (uint16_t)addr);
+
+		for (j = 0; j < (640 / 32); j++)
+			*(out + j) = *(in + j);
+	}
+}
+
+/*
+ * Display a graphical splash screen.
+ */
+void vgadisplayfile(FILE *_fd)
+{
+	char *p;
+	int size;
+
+	fd = _fd;
+
+	/*
+	 * This is a cheap and easy way to make sure the screen is
+	 * cleared in case we were in graphics mode aready.
+	 */
+	vgaclearmode();
+	vgasetmode();
+
+	size = 4+2*2+16*3;
+	p = (char *)&LSSHeader;
+
+	/* Load the header */
+	while (size--)
+		*p = getc(fd);
+
+	if (*p != EOF) {
+		com32sys_t ireg, oreg;
+		uint16_t rows;
+		int i;
+
+		/* The header WILL be in the first chunk. */
+		if (LSSMagic != 0x1413f33d)
+			return;
+
+		memset(&ireg, 0, sizeof(ireg));
+
+		/* Color map offset */
+		ireg.edx.w[0] = offsetof(lssheader_t, GraphColorMap);
+
+		ireg.eax.w[0] = 0x1012;	       /* Set RGB registers */
+		ireg.ebx.w[0] = 0;	       /* First register number */
+		ireg.ecx.w[0] = 16;	       /* 16 registers */
+		__intcall(0x10, &ireg, &oreg);
+
+		/* Number of pixel rows */
+		rows = (GraphYSize + VGAFontSize) - 1;
+		rows = rows / VGAFontSize;
+		if (rows >= VidRows)
+			rows = VidRows - 1;
+
+		memset(&ireg, 0, sizeof(ireg));
+
+		ireg.edx.b[1] = rows;
+		ireg.eax.b[1] = 2;
+		ireg.ebx.w[0] = 0;
+
+		/* Set cursor below image */
+		__intcall(0x10, &ireg, &oreg);
+
+		rows = GraphYSize; /* Number of graphics rows */
+		VGAPos = 0;
+
+		for (i = 0; i < rows; i++) {
+			/* Pre-clear the row buffer */
+			memset(VGARowBuffer, 0, 640);
+
+			/* Decode one row */
+			rledecode(VGARowBuffer, GraphXSize);
+
+			packedpixel2vga(VGARowBuffer, VGAPlaneBuffer, 640);
+			outputvga(VGAPlaneBuffer, MK_PTR(0x0A000, VGAPos));
+			VGAPos += 640/8;
+		}
+	}
+}
+
+/*
+ * Disable VGA graphics.
+ */
+void vgaclearmode(void)
+{
+	com32sys_t ireg, oreg;
+
+	/* Already in text mode? */
+	if (!UsingVGA)
+		return;
+
+	if (UsingVGA & 0x4) {
+		/* VESA return to normal video mode */
+		memset(&ireg, 0, sizeof(ireg));
+
+		ireg.eax.w[0] = 0x4F02; /* Set SuperVGA video mode */
+		ireg.ebx.w[0] = 0x0003;
+		__intcall(0x10, &ireg, &oreg);
+	}
+
+	/* Return to normal video mode */
+	memset(&ireg, 0, sizeof(ireg));
+	ireg.eax.w[0] = 0x0003;
+	__intcall(0x10, &ireg, &oreg);
+
+	UsingVGA = 0;
+
+	ScrollAttribute = 0x7;
+	/* Restore text font/data */
+	use_font();
+}
+
+static void vgacursorcommon(char data)
+{
+	if (UsingVGA) {
+		com32sys_t ireg;
+
+		ireg.eax.b[0] = data;
+		ireg.eax.b[1] = 0x09;
+		ireg.ebx.w[0] = 0x0007;
+		ireg.ecx.w[0] = 1;
+		__intcall(0x10, &ireg, NULL);
+	}
+}
+
+void vgahidecursor(void)
+{
+	vgacursorcommon(' ');
+}
+
+void vgashowcursor(void)
+{
+	vgacursorcommon('_');
+}
+
+void pm_usingvga(com32sys_t *regs)
+{
+	if (regs->eax.w[0] > 0x0F) {
+		/* Unknown flags = failure */
+		set_flags(regs, EFLAGS_CF);
+		return;
+	}
+
+	UsingVGA = regs->eax.b[0];
+	GXPixCols = regs->ecx.w[0];
+	GXPixRows = regs->edx.w[0];
+
+	if (UsingVGA & 0x08)
+		regs->eflags.l &= ~EFLAGS_CF;
+	else {
+		adjust_screen();
+		set_flags(regs, EFLAGS_CF);
+	}
+}
diff --git a/core/graphics.inc b/core/graphics.inc
deleted file mode 100644
index a8d2851..0000000
--- a/core/graphics.inc
+++ /dev/null
@@ -1,353 +0,0 @@
-;; -----------------------------------------------------------------------
-;;
-;;   Copyright 1994-2008 H. Peter Anvin - All Rights Reserved
-;;
-;;   This program is free software; you can redistribute it and/or modify
-;;   it under the terms of the GNU General Public License as published by
-;;   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
-;;   Boston MA 02111-1307, USA; either version 2 of the License, or
-;;   (at your option) any later version; incorporated herein by reference.
-;;
-;; -----------------------------------------------------------------------
-
-; ----------------------------------------------------------------------------
-;  VGA splash screen code
-; ----------------------------------------------------------------------------
-
-;
-; vgadisplayfile:
-;	Display a graphical splash screen.
-;	The file is already opened on the top of the getc stack.
-;
-;	Assumes CS == DS == ES.
-;
-		section .text16
-
-vgadisplayfile:
-		; This is a cheap and easy way to make sure the screen is
-		; cleared in case we were in graphics mode already
-		call vgaclearmode
-		call vgasetmode
-		jnz .error_nz
-
-.graphalready:
-		; Load the header.
-		mov cx,4+2*2+16*3
-		mov di,LSSHeader
-.gethdr:
-		call getc
-		stosb
-		loop .gethdr
-		jc .error
-
-		; The header WILL be in the first chunk.
-		cmp dword [LSSMagic],0x1413f33d	; Magic number
-.error_nz:	jne .error
-
-		mov dx,GraphColorMap		; Color map offset
-		mov ax,1012h			; Set RGB registers
-		xor bx,bx			; First register number
-		mov cx,16			; 16 registers
-		int 10h
-
-.movecursor:
-		mov ax,[GraphYSize]		; Number of pixel rows
-		mov dx,[VGAFontSize]
-		add ax,dx
-		dec ax
-		div dl
-		xor dx,dx			; Set column to 0
-		cmp al,[VidRows]
-		jb .rowsok
-		mov al,[VidRows]
-		dec al
-.rowsok:
-		mov dh,al
-		mov ah,2
-		xor bx,bx
-		int 10h				; Set cursor below image
-
-		mov cx,[GraphYSize]		; Number of graphics rows
-		mov word [VGAPos],0
-
-.drawpixelrow:
-		push cx
-		mov di,VGARowBuffer
-		; Pre-clear the row buffer
-		push di
-		push di
-		mov cx,640/4
-		xor eax,eax
-		rep stosd
-		pop di
-		mov cx,[GraphXSize]
-		call rledecode			; Decode one row
-		pop si
-		mov di,VGAPlaneBuffer
-		push di
-		mov bp,640
-		call packedpixel2vga
-		pop si
-		push es
-		mov di,0A000h			; VGA segment
-		mov es,di
-		mov di,[VGAPos]
-		call outputvga
-		pop es
-		add word [VGAPos],640/8
-		pop cx
-		loop .drawpixelrow
-
-.error:
-		jmp close			; Tailcall!
-
-;
-; rledecode:
-;	Decode a pixel row in RLE16 format.
-;
-; getc stack	-> input
-; CX		-> pixel count
-; ES:DI		-> output (packed pixel)
-;
-rledecode:
-		xor dx,dx		; DL = last pixel, DH = nybble buffer
-.loop:
-		call .getnybble
-		cmp al,dl
-		je .run			; Start of run sequence
-		stosb
-		mov dl,al
-		dec cx
-		jnz .loop
-.done:
-		ret
-.run:
-		xor bx,bx
-		call .getnybble
-		or bl,al
-		jz .longrun
-.dorun:
-		push cx
-		mov cx,bx
-		mov al,dl
-		rep stosb
-		pop cx
-		sub cx,bx
-		ja .loop
-		jmp short .done
-.longrun:
-		call .getnybble
-		mov bl,al
-		call .getnybble
-		shl al,4
-		or bl,al
-		add bx,16
-		jmp short .dorun
-
-.getnybble:
-		test dh,10h
-		jz .low
-		and dh,0Fh
-		mov al,dh
-		ret
-.low:
-		call getc
-		mov dh,al
-		shr dh,4
-		or dh,10h		; Nybble already read
-		and al,0Fh
-		ret
-
-;
-; packedpixel2vga:
-;	Convert packed-pixel to VGA bitplanes
-;
-; DS:SI -> packed pixel string
-; BP    -> pixel count (multiple of 8)
-; DS:DI -> output (four planes)
-;
-packedpixel2vga:
-		xor cx,cx
-.planeloop:
-		inc cx
-		push si
-		push bp
-.loop1:
-		mov bx,8
-.loop2:
-		lodsb
-		shr al,cl
-		rcl dl,1		; VGA is bigendian.  Sigh.
-		dec bx
-		jnz .loop2
-		mov [di],dl
-		inc di
-		sub bp,byte 8
-		ja .loop1
-		pop bp
-		pop si
-		cmp cl,3
-		jbe .planeloop
-		ret
-
-;
-; outputvga:
-;	Output four subsequent lines of VGA data
-;
-; DS:SI	-> four planes @ 640/8=80 bytes
-; ES:DI	-> pointer into VGA memory
-;
-outputvga:
-		mov dx,3C4h	; VGA Sequencer Register select port
-		mov al,2	; Sequencer mask
-		out dx,al	; Select the sequencer mask
-		inc dx		; VGA Sequencer Register data port
-		dec ax		; AL <- 1
-.loop1:
-		out dx,al	; Select the bit plane to write
-		push di
-		mov cx,640/32
-		rep movsd
-		pop di
-		add ax,ax
-		cmp al,8
-		jbe .loop1
-		ret
-
-;
-; vgasetmode:
-;	Enable VGA graphics, if possible; return ZF=1 on success
-;	DS must be set to the base segment; ES is set to DS.
-;
-vgasetmode:
-		push ds
-		pop es
-		mov al,[UsingVGA]
-		cmp al,01h
-		je .success		; Nothing to do...
-		test al,04h
-		jz .notvesa
-		; We're in a VESA mode, which means VGA; use VESA call
-		; to revert the mode, and then call the conventional
-		; mode-setting for good measure...
-		mov ax,4F02h
-		mov bx,0012h
-		int 10h
-		jmp .setmode
-.notvesa:
-		mov ax,1A00h		; Get video card and monitor
-		xor bx,bx
-		int 10h
-		sub bl, 7		; BL=07h and BL=08h OK
-		cmp bl, 1
-		ja .error		; ZF=0
-;		mov bx,TextColorReg
-;		mov dx,1009h		; Read color registers
-;		int 10h
-.setmode:
-		mov ax,0012h		; Set mode = 640x480 VGA 16 colors
-		int 10h
-		mov dx,linear_color
-		mov ax,1002h		; Write color registers
-		int 10h
-		mov [UsingVGA], byte 1
-
-		; Set GXPixCols and GXPixRows
-		mov dword [GXPixCols],640+(480 << 16)
-
-		call use_font		; Set graphics font/data
-		mov byte [ScrollAttribute], 00h
-
-.success:
-		xor ax,ax		; Set ZF
-.error:
-		ret
-
-;
-; vgaclearmode:
-;	Disable VGA graphics.  It is not safe to assume any value
-;	for DS or ES.
-;
-vgaclearmode:
-		push ds
-		push es
-		pushad
-		mov ax,cs
-		mov ds,ax
-		mov es,ax
-		mov al,[UsingVGA]
-		and al,al		; Already in text mode?
-		jz .done
-		test al,04h
-		jz .notvesa
-		mov ax,4F02h		; VESA return to normal video mode
-		mov bx,0003h
-		int 10h
-.notvesa:
-		mov ax,0003h		; Return to normal video mode
-		int 10h
-;		mov dx,TextColorReg	; Restore color registers
-;		mov ax,1002h
-;		int 10h
-		mov [UsingVGA], byte 0
-
-		mov byte [ScrollAttribute], 07h
-		call use_font		; Restore text font/data
-.done:
-		popad
-		pop es
-		pop ds
-		ret
-
-;
-; vgashowcursor/vgahidecursor:
-;	If VGA graphics is enabled, draw a cursor/clear a cursor
-;
-vgashowcursor:
-		pushad
-		mov al,'_'
-		jmp short vgacursorcommon
-vgahidecursor:
-		pushad
-		mov al,' '
-vgacursorcommon:
-		cmp [UsingVGA], byte 1
-		jne .done
-		mov ah,09h
-		mov bx,0007h
-		mov cx,1
-		int 10h
-.done:
-		popad
-		ret
-
-
-		section .data16
-		; Map colors to consecutive DAC registers
-linear_color	db 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0
-
-		; See comboot.doc, INT 22h AX=0017h for the semantics
-		; of this byte.
-UsingVGA	db 0
-
-		section .bss16
-		alignb 4
-LSSHeader	equ $
-LSSMagic	resd 1			; Magic number
-GraphXSize	resw 1			; Width of splash screen file
-GraphYSize	resw 1			; Height of splash screen file
-GraphColorMap	resb 3*16
-VGAPos		resw 1			; Pointer into VGA memory
-VGAFilePtr	resw 1			; Pointer into VGAFileBuf
-; TextColorReg	resb 17			; VGA color registers for text mode
-%if IS_SYSLINUX
-VGAFileBuf	resb FILENAME_MAX+2	; Unmangled VGA image name
-%else
-VGAFileBuf	resb FILENAME_MAX	; Unmangled VGA image name
-%endif
-VGAFileBufEnd	equ $
-VGAFileMBuf	resb FILENAME_MAX	; Mangled VGA image name
-
-		alignb 4
-VGARowBuffer	resb 640+80		; Decompression buffer
-VGAPlaneBuffer	resb (640/8)*4		; Plane buffers
diff --git a/core/idle.inc b/core/idle.inc
index 9677c82..ad26a10 100644
--- a/core/idle.inc
+++ b/core/idle.inc
@@ -22,6 +22,7 @@ reset_idle:
 		sti		; Guard against BIOS/PXE brokenness...
 		ret
 
+		global do_idle
 do_idle:
 		push eax
 		push ds
@@ -42,11 +43,11 @@ do_idle:
 		mov cx,16
 .errloop:
 		ss lodsw
-		call writehex4
+		pm_call pm_writehex4
 		dec cx
 		jz .endloop
 		mov al,' '
-		call writechr
+		pm_call pm_writechr
 		jmp .errloop
 .endloop:
 		call crlf
diff --git a/core/include/bios.h b/core/include/bios.h
new file mode 100644
index 0000000..3c49cf2
--- /dev/null
+++ b/core/include/bios.h
@@ -0,0 +1,105 @@
+/*
+ * -----------------------------------------------------------------------
+ *
+ *   Copyright 1994-2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * -----------------------------------------------------------------------
+ *
+ *
+ * bios.h
+ *
+ * Header file for the BIOS data structures etc.
+ */
+
+#ifndef _BIOS_H
+#define _BIOS_H
+
+/*
+ * Interrupt vectors
+ */
+#define BIOS_timer_hook	(4 * 0x1C)
+#define fdctab		(4 * 0x1E)
+#define fdctab1		fdctab
+#define fdctab2		(fdctab + 2)
+
+#define serial_base	0x0400	/* Base address for 4 serial ports */
+#define BIOS_fbm	0x0413	/* Free Base Memory (kilobytes) */
+#define BIOS_page	0x0462	/* Current video page */
+#define BIOS_timer	0x046C	/* Timer ticks */
+#define BIOS_magic	0x0472	/* BIOS reset magic */
+#define BIOS_vidrows	0x0484	/* Number of screen rows */
+
+#define serial_buf_size		4096
+#define IO_DELAY_PORT		0x80 /* Invalid port (we hope!) */
+
+static inline void io_delay(void)
+{
+	outb(0x0, IO_DELAY_PORT);
+	outb(0x0, IO_DELAY_PORT);
+}
+
+/* conio.c */
+extern unsigned short SerialPort;
+extern unsigned char FlowIgnore;
+extern uint8_t ScrollAttribute;
+extern uint16_t DisplayCon;
+
+/*
+ * Sometimes we need to access screen coordinates as separate 8-bit
+ * entities and sometimes we need to use them as 16-bit entities. Using
+ * this structure allows the compiler to do it for us.
+ */
+union screen {
+	struct {
+		uint8_t col;	/* Cursor column for message file */
+		uint8_t row;	/* Cursor row for message file */
+	} b;
+	uint16_t dx;
+};
+extern union screen _cursor;
+extern union screen _screensize;
+
+#define CursorDX	_cursor.dx
+#define CursorCol	_cursor.b.col
+#define CursorRow	_cursor.b.row
+
+#define ScreenSize	_screensize.dx
+#define VidCols		_screensize.b.col
+#define VidRows		_screensize.b.row
+
+extern void write_serial(char data);
+
+/* font.c */
+extern uint16_t VGAFontSize;
+extern void use_font(void);
+extern void bios_adjust_screen(void);
+
+/* graphics.c */
+#ifdef IS_SYSLINUX
+#define VGA_FILE_BUF_SIZE	(FILENAME_MAX + 2)
+#else
+#define VGA_FILE_BUF_SIZE	FILENAME_MAX
+#endif
+
+extern uint8_t UsingVGA;
+extern uint16_t VGAPos;
+extern uint16_t *VGAFilePtr;
+extern char VGAFileBuf[VGA_FILE_BUF_SIZE];
+extern char VGAFileMBuf[];
+extern void vgaclearmode(void);
+extern void vgadisplayfile(FILE *fd);
+
+/* serirq.c */
+extern unsigned char *SerialHead;
+extern unsigned char *SerialTail;
+
+extern void bios_init(void);
+extern void bios_cleanup_hardware(void);
+
+#endif /* _BIOS_H */
diff --git a/core/include/core.h b/core/include/core.h
index 4f5f843..9fc0ce1 100644
--- a/core/include/core.h
+++ b/core/include/core.h
@@ -24,6 +24,8 @@ extern char ConfigFile[];
 extern char syslinux_banner[];
 extern char copyright_str[];
 
+extern char aux_seg[];
+
 /* diskstart.inc isolinux.asm*/
 extern void getlinsec(void);
 
diff --git a/core/init.c b/core/init.c
new file mode 100644
index 0000000..27b9e46
--- /dev/null
+++ b/core/init.c
@@ -0,0 +1,77 @@
+#include <core.h>
+#include <com32.h>
+#include <sys/io.h>
+#include <fs.h>
+#include <bios.h>
+
+static uint16_t min_lowmem_heap = 65536;
+extern char __lowmem_heap[];
+uint8_t KbdFlags;		/* Check for keyboard escapes */
+
+static inline void check_escapes(void)
+{
+	com32sys_t ireg, oreg;
+
+	ireg.eax.b[1] = 0x02;	/* Check keyboard flags */
+	__intcall(0x16, &ireg, &oreg);
+
+	KbdFlags = oreg.eax.b[0];
+
+	/* Ctrl->skip 386 check */
+	if (oreg.eax.b[0] & 0x04) {
+		/*
+		 * Now check that there is sufficient low (DOS) memory
+		 *
+		 * NOTE: Linux doesn't use all of real_mode_seg, but we use
+		 * the same segment for COMBOOT images, which can use all 64K.
+		 */
+		uint16_t mem;
+
+		__intcall(0x12, &ireg, &oreg);
+
+		mem = ((uint16_t)__lowmem_heap) + min_lowmem_heap + 1023;
+		mem = mem >> 10;
+
+		if (mem < oreg.eax.w[0]) {
+			char buf[256];
+
+			snprintf(buf, sizeof(buf),
+				 "It appears you computer has less than "
+				 "%dK of low (DOS)\nRAM.  Syslinux "
+				 "needs at least this amount to boot.  "
+				 "If you get\nthis message in error, "
+				 "hold down the Ctrl key while\nbooting, "
+				 "and I will take your word for it.\n",
+				 mem);
+			writestr(buf);
+			kaboom();
+		}
+	}
+}
+
+extern uint32_t BIOS_timer_next;
+extern uint32_t timer_irq;
+static inline void bios_timer_init(void)
+{
+	unsigned long next;
+	uint32_t *hook = BIOS_timer_hook;
+
+	next = *hook;
+	BIOS_timer_next = next;
+	*hook = &timer_irq;
+}
+
+void init(com32sys_t *regs)
+{
+	/* Initialize timer */
+	bios_timer_init();
+
+	adjust_screen();
+	printf_init();
+
+	/* Init the memory subsystem */
+	mem_init();
+
+	/* CPU-dependent initialization and related checks. */
+	check_escapes();
+}
diff --git a/core/init.inc b/core/init.inc
index cce4327..83d6fd6 100644
--- a/core/init.inc
+++ b/core/init.inc
@@ -28,11 +28,8 @@ common_init:
 		cmp eax,__pm_code_len
 		jne kaboom
 
-;
-; Initialize timer
-;
-		call timer_init
-
+		extern init
+		pm_call init
 ;
 ; Initialize configuration information
 ;
@@ -44,63 +41,12 @@ common_init:
 		call comboot_setup_api
 
 ;
-; Now set up screen parameters
-;
-		call adjust_screen
-		pm_call printf_init
-
-;
 ; Inite the memmory subsystem
 ;
-		pm_call mem_init
+;		pm_call mem_init
 		mov eax,[HighMemSize]
 		mov [VKernelEnd],eax
 
-;
-; CPU-dependent initialization and related checks.
-;
-check_escapes:
-		mov ah,02h			; Check keyboard flags
-		int 16h
-		mov [KbdFlags],al		; Save for boot prompt check
-		test al,04h			; Ctrl->skip 386 check
-		jnz skip_checks
-
-;
-; Now check that there is sufficient low (DOS) memory
-;
-; NOTE: Linux doesn't use all of real_mode_seg, but we use the same
-; segment for COMBOOT images, which can use all 64K
-;
-		int 12h
-		mov edx,__lowmem_heap + min_lowmem_heap + 1023
-		shr edx,10
-		cmp ax,dx
-		jae enough_ram
-		mov ax,dx
-		mov si,err_noram
-		mov cl,10
-		div cl
-		add [si+err_noram.size-err_noram+2],ah
-		cbw
-		div cl
-		add [si+err_noram.size-err_noram],ax
-		call writestr_early
-		jmp kaboom
-enough_ram:
-skip_checks:
-
-		section .data16
-err_noram	db 'It appears your computer has less than '
-.size		db '000'
-		db 'K of low ("DOS")'
-		db CR, LF
-		db 'RAM.  Syslinux needs at least this amount to boot.  If you get'
-		db CR, LF
-		db 'this message in error, hold down the Ctrl key while'
-		db CR, LF
-		db 'booting, and I will take your word for it.', CR, LF, 0
-
 		section .text16
 ;
 ; The code to decompress the PM code and initialize other segments.
diff --git a/core/isolinux.asm b/core/isolinux.asm
index 895468c..b0b21a3 100644
--- a/core/isolinux.asm
+++ b/core/isolinux.asm
@@ -1169,6 +1169,22 @@ ROOT_FS_OPS:
 
 		section .text16
 
+%ifdef DEBUG_TRACERS
+;
+; debug hack to print a character with minimal code impact
+;
+debug_tracer:	pushad
+		pushfd
+		mov bp,sp
+		mov bx,[bp+9*4]		; Get return address
+		mov al,[cs:bx]		; Get data byte
+		inc word [bp+9*4]	; Return to after data byte
+		call writechr
+		popfd
+		popad
+		ret
+%endif	; DEBUG_TRACERS
+
 ;
 ; Now we have the config file open.  Parse the config file and
 ; run the user interface.
diff --git a/core/plaincon.c b/core/plaincon.c
new file mode 100644
index 0000000..a12d551
--- /dev/null
+++ b/core/plaincon.c
@@ -0,0 +1,32 @@
+/*
+ * writechr:	Write a single character in AL to the console without
+ *		mangling any registers; handle video pages correctly.
+ */
+#include <sys/io.h>
+#include <fs.h>
+#include <com32.h>
+#include "bios.h"
+
+void writechr(char data)
+{
+	com32sys_t ireg, oreg;
+
+	write_serial(data);	/* write to serial port if needed */
+
+	if (UsingVGA & 0x8)
+		vgaclearmode();
+
+	if (!(DisplayCon & 0x1))
+		return;
+
+	ireg.eax.b[0] = data;
+	ireg.eax.b[1] = 0xE;
+	ireg.ebx.b[0] = 0x07;	/* attribute */
+	ireg.ebx.b[1] = *(uint8_t *)BIOS_page; /* current page */
+	__intcall(0x10, &ireg, &oreg);
+}
+
+void pm_writechr(com32sys_t *regs)
+{
+	writechr(regs->eax.b[0]);
+}
diff --git a/core/plaincon.inc b/core/plaincon.inc
deleted file mode 100644
index c41629d..0000000
--- a/core/plaincon.inc
+++ /dev/null
@@ -1,24 +0,0 @@
-;
-; writechr:	Write a single character in AL to the console without
-;		mangling any registers; handle video pages correctly.
-;
-		section .text16
-
-writechr:
-		call write_serial	; write to serial port if needed
-		pushfd
-		test byte [cs:UsingVGA], 08h
-		jz .videook
-		call vgaclearmode
-.videook:
-		test byte [cs:DisplayCon], 01h
-		jz .nothing
-		pushad
-		mov ah,0Eh
-		mov bl,07h		; attribute
-		mov bh,[cs:BIOS_page]	; current page
-		int 10h
-		popad
-.nothing:
-		popfd
-		ret
diff --git a/core/pm.inc b/core/pm.inc
index 9584cda..c6f3c52 100644
--- a/core/pm.inc
+++ b/core/pm.inc
@@ -328,7 +328,8 @@ a20_fast:
 		jnz a20_dunno		; Did we get the wrong type?
 
 		mov si, err_a20
-		jmp abort_load
+		pm_call pm_writestr
+		jmp kaboom
 
 		section .data16
 err_a20		db CR, LF, 'A20 gate not responding!', CR, LF, 0
diff --git a/core/pxelinux.asm b/core/pxelinux.asm
index 8c56022..8a95d1e 100644
--- a/core/pxelinux.asm
+++ b/core/pxelinux.asm
@@ -339,7 +339,7 @@ kaboom:
 		je .wait3
 		loop .wait2,ecx
 		mov al,'.'
-		call writechr
+		pm_call pm_writechr
 		pop cx
 		loop .wait1
 .keypress:
@@ -492,6 +492,18 @@ gpxe_unload:
 .plain:
 		ret
 
+writestr_early:
+		pm_call pm_writestr
+		ret
+
+pollchar:
+		pm_call pm_pollchar
+		ret
+
+getchar:
+		pm_call pm_getchar
+		ret
+
 		section .data16
 		alignz 4
 pxe_file_exit_hook:
@@ -507,9 +519,6 @@ pxe_file_exit_hook:
 ; -----------------------------------------------------------------------------
 
 %include "common.inc"		; Universal modules
-%include "writestr.inc"		; String output
-writestr_early	equ writestr
-%include "writehex.inc"		; Hexadecimal output
 %include "rawcon.inc"		; Console I/O w/o using the console functions
 
 ; -----------------------------------------------------------------------------
diff --git a/core/serirq.c b/core/serirq.c
new file mode 100644
index 0000000..767099e
--- /dev/null
+++ b/core/serirq.c
@@ -0,0 +1,204 @@
+/*
+ * -----------------------------------------------------------------------
+ *
+ *   Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * -----------------------------------------------------------------------
+ *
+ * serirq.c
+ *
+ * Serial port IRQ code
+ *
+ * We don't know what IRQ, if any, we have, so map all of them...
+ */
+#include <sys/io.h>
+#include <string.h>
+
+#include <fs.h>
+#include "bios.h"
+
+static char serial_buf[serial_buf_size];
+
+static unsigned short SerialIRQPort; /* Serial port w IRQ service */
+unsigned char *SerialHead = serial_buf;    /* Head of serial port rx buffer */
+unsigned char *SerialTail = serial_buf;    /* Tail of serial port rx buffer */
+
+static unsigned char IRQMask[2];	     /* PIC IRQ mask status */
+
+static unsigned int oldirq[16];
+
+typedef void (*irqhandler_t)(void);
+
+void sirq_cleanup(void);
+
+static void irq_common(unsigned short old_irq)
+{
+	unsigned char *dst;
+	irqhandler_t next;
+	char val;
+
+	dst = (unsigned char *)SerialHead;
+	next = (irqhandler_t)oldirq[old_irq];
+
+	/* LSR */
+	val = inb(SerialPort + 5);
+
+	/* Received data */
+	while (val & 1) {
+		/* RDR */
+		*dst++ = inb(SerialPort);
+		/* LSR */
+		val = inb(SerialPort + 5);
+		if ((val & FlowIgnore) == FlowIgnore) {
+			/* Wrap around if necessary */
+			dst = (unsigned char *)((unsigned long)dst & (serial_buf_size - 1));
+
+			/* Would this cause overflow? */
+			if (dst != SerialTail)
+				SerialHead = dst;
+		}
+	}
+
+	/* Chain to next handler */
+	next();
+}
+
+#define SERIAL_IRQ_HANDLER(n) \
+	static void serstub_irq##n(void)	\
+	{					\
+		irq_common(n);			\
+	}
+
+SERIAL_IRQ_HANDLER(0);
+SERIAL_IRQ_HANDLER(1);
+SERIAL_IRQ_HANDLER(2);
+SERIAL_IRQ_HANDLER(3);
+SERIAL_IRQ_HANDLER(4);
+SERIAL_IRQ_HANDLER(5);
+SERIAL_IRQ_HANDLER(6);
+SERIAL_IRQ_HANDLER(7);
+SERIAL_IRQ_HANDLER(8);
+SERIAL_IRQ_HANDLER(9);
+SERIAL_IRQ_HANDLER(10);
+SERIAL_IRQ_HANDLER(11);
+SERIAL_IRQ_HANDLER(12);
+SERIAL_IRQ_HANDLER(13);
+SERIAL_IRQ_HANDLER(14);
+SERIAL_IRQ_HANDLER(15);
+
+static inline void save_irq_vectors(uint32_t *src, uint32_t *dst)
+{
+	int i;
+
+	for (i = 0; i < 8; i++)
+		*dst++ = *src++;
+}
+
+static inline void install_irq_vectors(uint32_t *dst, int first)
+{
+	if (first) {
+		*dst++ = (uint32_t)serstub_irq0;
+		*dst++ = (uint32_t)serstub_irq1;
+		*dst++ = (uint32_t)serstub_irq2;
+		*dst++ = (uint32_t)serstub_irq3;
+		*dst++ = (uint32_t)serstub_irq4;
+		*dst++ = (uint32_t)serstub_irq5;
+		*dst++ = (uint32_t)serstub_irq6;
+		*dst++ = (uint32_t)serstub_irq7;
+	} else {
+		*dst++ = (uint32_t)serstub_irq8;
+		*dst++ = (uint32_t)serstub_irq9;
+		*dst++ = (uint32_t)serstub_irq10;
+		*dst++ = (uint32_t)serstub_irq11;
+		*dst++ = (uint32_t)serstub_irq12;
+		*dst++ = (uint32_t)serstub_irq13;
+		*dst++ = (uint32_t)serstub_irq14;
+		*dst++ = (uint32_t)serstub_irq15;
+	}
+}
+
+void sirq_install(void)
+{
+	char val, val2;
+
+	sirq_cleanup();
+
+	save_irq_vectors((uint32_t *)(4 * 0x8), oldirq);
+	save_irq_vectors((uint32_t *)(4 * 0x70), &oldirq[8]);
+
+	install_irq_vectors((uint32_t *)(4 * 0x8), 1);
+	install_irq_vectors((uint32_t *)(4 * 0x70), 0);
+
+	SerialIRQPort = SerialPort;
+
+	/* Clear DLAB (should already be...) */
+	outb(0x3, SerialIRQPort + 5);
+	io_delay();
+
+	/* Enable receive interrupt */
+	outb(0x1, SerialIRQPort + 1);
+	io_delay();
+
+	/*
+	 * Enable all the interrupt lines at the PIC. Some BIOSes only
+	 * enable the timer interrupts and other interrupts actively
+	 * in use by the BIOS.
+	 */
+
+	/* Secondary PIC mask register */
+	val = inb(0xA1);
+	val2 = inb(0x21);
+	IRQMask[0] = val;
+	IRQMask[1] = val2;
+
+	io_delay();
+
+	/* Remove all interrupt masks */
+	outb(0x21, 0);
+	outb(0xA1, 0);
+}
+
+void sirq_cleanup_nowipe(void)
+{
+	uint32_t *dst;
+	int i;
+
+	if (!SerialIRQPort)
+		return;
+
+	/* Clear DLAB */
+	outb(0x3, SerialIRQPort + 5);
+	io_delay();
+
+	/* Clear IER */
+	outb(0x0, SerialIRQPort + 1);
+	io_delay();
+
+	/* Restore PIC masks */
+	outb(IRQMask[0], 0x21);
+	outb(IRQMask[1], 0xA1);
+
+	/* Restore the original interrupt vectors */
+	dst = (uint32_t *)(4 * 0x8);
+	for (i = 0; i < 8; i++)
+		*dst++ = oldirq[i];
+
+	dst = (uint32_t *)(4 * 0x70);
+	for (i = 8; i < 16; i++)
+		*dst++ = oldirq[i];
+
+	/* No active interrupt system */
+	SerialIRQPort = 0;
+}
+
+void sirq_cleanup(void)
+{
+	sirq_cleanup_nowipe();
+	memcpy(SerialHead, 0x0, serial_buf_size);
+}
diff --git a/core/serirq.inc b/core/serirq.inc
deleted file mode 100644
index bd08b69..0000000
--- a/core/serirq.inc
+++ /dev/null
@@ -1,221 +0,0 @@
-;; -----------------------------------------------------------------------
-;;
-;;   Copyright 2009 Intel Corporation; author: H. Peter Anvin
-;;
-;;   This program is free software; you can redistribute it and/or modify
-;;   it under the terms of the GNU General Public License as published by
-;;   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
-;;   Boston MA 02111-1307, USA; either version 2 of the License, or
-;;   (at your option) any later version; incorporated herein by reference.
-;;
-;; -----------------------------------------------------------------------
-
-;;
-;; serirq.inc
-;;
-;; Serial port IRQ code
-;;
-;; We don't know what IRQ, if any, we have, so map all of them...
-;;
-
-		section .text16
-		bits 16
-		align 8
-
-		section .bss16
-		alignb 8
-
-%assign n 0
-%rep 16
-		section .text16
-serstub_irq %+ n :
-		push dword [cs:oldirq %+ n]
-		jmp short irq_common
-
-		section .bss16
-oldirq %+ n	resd 1
-%assign n n+1
-%endrep
-
-		section .text16
-irq_common:
-		pushf
-		push ax
-		push dx
-		mov dx,[cs:SerialPort]
-		add dx,5			; DX -> LSR
-		in al,dx
-		test al,1			; Received data
-		jnz .data
-.done:
-		pop dx
-		pop ax
-		popf
-		retf				; Chain to next handler
-.data:
-		push es
-		push di
-		mov ax,aux_seg + (aux.serial >> 4)
-		mov es,ax
-		mov di,[cs:SerialHead]
-.loop:
-		mov dx,[cs:SerialPort]		; DX -> RDR
-		in al,dx
-		stosb
-		mov ah,[cs:FlowIgnore]
-		add dx,5			; DX -> LSR
-		in al,dx
-		push ax
-		and al,ah
-		cmp al,ah
-		jne .drop
-		and di,serial_buf_size-1	; Wrap around if necessary
-		cmp di,[cs:SerialTail]		; Would this cause overflow?
-		je .drop			; If so, just drop the data
-		mov [cs:SerialHead],di
-.drop:
-		pop ax
-		test al,1			; More data?
-		jnz .loop
-.full:
-		pop di
-		pop es
-		jmp .done
-
-		section .bss16
-;
-; SerialIRQPort will generally track SerialPort, but will be 0 when an
-; IRQ service is not installed.
-;
-SerialIRQPort	resw 1			; Serial port w IRQ service
-SerialHead	resw 1			; Head of serial port rx buffer
-SerialTail	resw 1			; Tail of serial port rx buffer
-
-		section .bss16
-IRQMask		resw 1			; PIC IRQ mask status
-
-		section .text16
-
-		global sirq_install
-sirq_install:
-		pushad
-
-		call sirq_cleanup
-
-		; Save the old interrupt vectors
-		mov si,4*08h
-		mov di,oldirq0
-		mov cx,8
-		rep movsd
-		mov si,4*70h
-		mov cx,8
-		rep movsd
-
-		; Install new interrupt vectors
-		mov di,4*08h
-		mov cx,8
-		mov eax,serstub_irq0
-.pic0:
-		stosd
-		add ax,serstub_irq1 - serstub_irq0
-		loop .pic0
-		mov di,4*70h
-		mov cx,8
-.pic1:
-		stosd
-		add ax,serstub_irq1 - serstub_irq0
-		loop .pic1
-
-		mov bx,[SerialPort]
-		mov [SerialIRQPort],bx
-
-		lea dx,[bx+5]		; DX -> LCR
-		mov al,03h		; Clear DLAB (should already be...)
-		slow_out dx,al
-
-		lea dx,[bx+1]		; DX -> IER
-		mov al,1		; Enable receive interrupt
-		slow_out dx,al
-
-		;
-		; Enable all ther interupt lines at the PIC.  Some BIOSes
-		; only enable the timer interrupts and other interrupts
-		; actively in use by the BIOS.
-		;
-		in al,0xA1		; Secondary PIC mask register
-		mov ah,al
-		in al,0x21		; Primary PIC mask register
-		mov [IRQMask],ax
-
-		io_delay
-
-		xor ax,ax		; Remove all interrupt masks
-		out 0x21,al
-		out 0xA1,al
-
-		popad
-		ret
-
-		global sirq_cleanup_nowipe
-sirq_cleanup_nowipe:
-		pushad
-		push ds
-		push es
-		xor ax,ax
-		mov ds,ax
-		mov es,ax
-
-		mov bx,[SerialIRQPort]
-		and bx,bx
-		jz .done
-
-		lea dx,[bx+5]		; DX -> LCR
-		mov al,03h		; Clear DLAB (should already be...)
-		slow_out dx,al
-
-		lea dx,[bx+1]		; DX -> IER
-		xor ax,ax
-		slow_out dx,al		; Clear IER
-
-		; Restore PIC masks
-		mov ax,[IRQMask]
-		out 0x21,al
-		mov al,ah
-		out 0xA1,al
-
-		; Restore the original interrupt vectors
-		mov si,oldirq0
-		mov di,4*08h
-		mov cx,8
-		rep movsd
-		mov di,4*70h
-		mov cx,8
-		rep movsd
-
-		xor ax,ax
-		mov [SerialIRQPort],ax		; No active interrupt system
-
-.done:
-		pop es
-		pop ds
-		popad
-		ret
-
-sirq_cleanup:
-		call sirq_cleanup_nowipe
-		pushad
-		push es
-		; Just in case it might contain a password, erase the
-		; serial port receive buffer...
-		mov ax,aux_seg + (aux.serial >> 4)
-		mov es,ax
-		xor eax,eax
-		mov [cs:SerialHead],eax
-		mov cx,serial_buf_size >> 2
-		xor di,di
-		rep stosd
-		pop es
-		popad
-		ret
-
-		section .text16
diff --git a/core/timer.inc b/core/timer.inc
index b01ff91..2bf0a21 100644
--- a/core/timer.inc
+++ b/core/timer.inc
@@ -32,6 +32,7 @@ timer_init:
 		mov dword [BIOS_timer_hook],timer_irq
 		ret
 
+		global timer_cleanup
 timer_cleanup:
 		; Unhook INT 1Ch
 		mov eax,[BIOS_timer_next]
@@ -42,11 +43,13 @@ timer_cleanup:
 ; The specified frequency is 14.31818 MHz/12/65536; this turns out
 ; to be a period of 54.92542 ms, or 0x36.ece8(187c) hexadecimal.
 ;
+		global timer_irq
 timer_irq:
 		inc dword [cs:__jiffies]
 		add word  [cs:__ms_timer_adj],0xece8
 		adc dword [cs:__ms_timer],0x36
 		jmp 0:0
+		global BIOS_timer_next
 BIOS_timer_next	equ $-4
 
 		section .data16
diff --git a/core/ui.inc b/core/ui.inc
index b4b59b8..5dfeec4 100644
--- a/core/ui.inc
+++ b/core/ui.inc
@@ -731,6 +731,14 @@ CmdOptPtr       resw 1			; Pointer to first option on cmd line
 KbdFlags	resb 1			; Check for keyboard escapes
 FuncFlag	resb 1			; Escape sequences received from keyboard
 KernelType	resb 1			; Kernel type, from vkernel, if known
+		global KernelName
+KernelName	resb FILENAME_MAX	; Mangled name for kernel
+		section .config
+		global PXERetry
+PXERetry	dw 0			; Extra PXE retries
+		section .data16
+		global SerialNotice
+SerialNotice	db 1			; Only print this once
 
 		section .text16
 ;
@@ -753,9 +761,7 @@ KernelType	resb 1			; Kernel type, from vkernel, if known
 ;
 ; Abort loading code
 ;
-%include "abort.inc"
 
 ;
 ; Hardware cleanup common code
 ;
-%include "cleanup.inc"
diff --git a/core/writehex.c b/core/writehex.c
new file mode 100644
index 0000000..fde2703
--- /dev/null
+++ b/core/writehex.c
@@ -0,0 +1,70 @@
+/* -----------------------------------------------------------------------
+ *
+ *   Copyright 1994-2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * -----------------------------------------------------------------------
+ */
+#include <core.h>
+
+/*
+ * writehex.c
+ *
+ * Write hexadecimal numbers to the console
+ *
+ */
+
+static inline void __writehex(uint32_t h, int digits)
+{
+	while (digits) {
+		uint8_t shift;
+		uint8_t al;
+
+		shift = --digits;
+		al = ((h & 0x0f << shift) >> shift);
+		if (al < 10)
+			al += '0';
+		else
+			al += 'A' - 10;
+
+		writechr(al);
+	}
+}
+
+/*
+ * writehex[248]: Write a hex number in (AL, AX, EAX) to the console
+ */
+void writehex2(uint32_t h)
+{
+	__writehex(h, 2);
+}
+
+void writehex4(uint8_t h)
+{
+	__writehex(h, 4);
+}
+
+void writehex8(uint8_t h)
+{
+	__writehex(h, 8);
+}
+
+void pm_writehex2(com32sys_t *regs)
+{
+	writehex2(regs->eax.b[0]);
+}
+
+void pm_writehex4(com32sys_t *regs)
+{
+	writehex4(regs->eax.w[0]);
+}
+
+void pm_writehex8(com32sys_t *regs)
+{
+	writehex8(regs->eax.l);
+}


More information about the Syslinux-commits mailing list