From 18d9c7cd538a971ccadbc0276f3f5c5f8f1fc4ea Mon Sep 17 00:00:00 2001 From: okuji Date: Thu, 25 Sep 2003 20:15:53 +0000 Subject: [PATCH] 2003-09-25 Yoshinori K. Okuji I forgot to check in these changes for a long time. This adds incomplete support for VGA console, and this is still very buggy. Also, a lot of consideration is required for I18N, UNICODE, and VGA font issues. Therefore, assume that this is such that "better than nothing". * font/manager.c: New file. * include/pupa/font.h: Likewise. * include/pupa/i386/pc/vga.h: Likewise. * term/i386/pc/vga.c: Likewise. * util/unifont2pff.rb: Likewise. * conf/i386-pc.rmk (kernel_img_HEADERS): Added machine/vga.h. (pkgdata_MODULES): Added vga.mod and font.mod. (vga_mod_SOURCES): New variables. (vga_mod_CFLAGS): Likewise. (font_mod_SOURCES): Likewise. (font_mod_CFLAGS): Likewise. * include/pupa/err.h (PUPA_ERR_BAD_FONT): New constant. * include/pupa/term.h: Include pupa/err.h. (struct pupa_term): Added init and fini. Changed the argument of putchar to pupa_uint32_t. * include/pupa/i386/pc/console.h: Include pupa/symbol.h. (pupa_console_real_putchar): New prototype. (pupa_console_putchar): Removed. (pupa_console_checkkey): Exported. (pupa_console_getkey): Likewise. * kern/misc.c (pupa_vsprintf): Add support for UNICODE characters. * kern/term.c (pupa_term_set_current): Rewritten. (pupa_putchar): Likewise. (pupa_putcode): New function. * kern/i386/pc/startup.S (pupa_console_putchar): Renamed to ... (pupa_console_real_putchar): ... this. (pupa_vga_set_mode): New function. (pupa_vga_get_font): Likewise. * normal/command.c: Include pupa/term.h. (terminal_command): New function. (pupa_command_init): Register the command "terminal". * normal/menu.c (DISP_LEFT): Changed to a UNICODE value. (DISP_UP): Likewise. (DISP_RIGHT): Likewise. (DISP_DOWN): Likewise. (DISP_HLINE): Likewise. (DISP_VLINE): Likewise. (DISP_UL): Likewise. (DISP_UR): Likewise. (DISP_LL): Likewise. (DISP_LR): Likewise. * term/i386/pc/console.c (pupa_console_putchar): New function. --- ChangeLog | 62 ++++ conf/i386-pc.mk | 122 +++++++- conf/i386-pc.rmk | 13 +- font/manager.c | 243 +++++++++++++++ include/grub/err.h | 1 + include/grub/font.h | 30 ++ include/grub/i386/pc/console.h | 7 +- include/grub/i386/pc/vga.h | 31 ++ include/grub/term.h | 18 +- kern/i386/pc/startup.S | 61 +++- kern/misc.c | 56 +++- kern/term.c | 95 +++++- normal/command.c | 49 +++ normal/menu.c | 45 +-- term/i386/pc/console.c | 52 +++- term/i386/pc/vga.c | 529 +++++++++++++++++++++++++++++++++ util/unifont2pff.rb | 79 +++++ 17 files changed, 1443 insertions(+), 50 deletions(-) create mode 100644 font/manager.c create mode 100644 include/grub/font.h create mode 100644 include/grub/i386/pc/vga.h create mode 100644 term/i386/pc/vga.c create mode 100644 util/unifont2pff.rb diff --git a/ChangeLog b/ChangeLog index 6a461305e..c2b964ded 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,65 @@ +2003-09-25 Yoshinori K. Okuji + + I forgot to check in these changes for a long time. This adds + incomplete support for VGA console, and this is still very + buggy. Also, a lot of consideration is required for I18N, + UNICODE, and VGA font issues. Therefore, assume that this is + such that "better than nothing". + + * font/manager.c: New file. + * include/pupa/font.h: Likewise. + * include/pupa/i386/pc/vga.h: Likewise. + * term/i386/pc/vga.c: Likewise. + * util/unifont2pff.rb: Likewise. + + * conf/i386-pc.rmk (kernel_img_HEADERS): Added machine/vga.h. + (pkgdata_MODULES): Added vga.mod and font.mod. + (vga_mod_SOURCES): New variables. + (vga_mod_CFLAGS): Likewise. + (font_mod_SOURCES): Likewise. + (font_mod_CFLAGS): Likewise. + + * include/pupa/err.h (PUPA_ERR_BAD_FONT): New constant. + + * include/pupa/term.h: Include pupa/err.h. + (struct pupa_term): Added init and fini. + Changed the argument of putchar to pupa_uint32_t. + + * include/pupa/i386/pc/console.h: Include pupa/symbol.h. + (pupa_console_real_putchar): New prototype. + (pupa_console_putchar): Removed. + (pupa_console_checkkey): Exported. + (pupa_console_getkey): Likewise. + + * kern/misc.c (pupa_vsprintf): Add support for UNICODE + characters. + + * kern/term.c (pupa_term_set_current): Rewritten. + (pupa_putchar): Likewise. + (pupa_putcode): New function. + + * kern/i386/pc/startup.S (pupa_console_putchar): Renamed to ... + (pupa_console_real_putchar): ... this. + (pupa_vga_set_mode): New function. + (pupa_vga_get_font): Likewise. + + * normal/command.c: Include pupa/term.h. + (terminal_command): New function. + (pupa_command_init): Register the command "terminal". + + * normal/menu.c (DISP_LEFT): Changed to a UNICODE value. + (DISP_UP): Likewise. + (DISP_RIGHT): Likewise. + (DISP_DOWN): Likewise. + (DISP_HLINE): Likewise. + (DISP_VLINE): Likewise. + (DISP_UL): Likewise. + (DISP_UR): Likewise. + (DISP_LL): Likewise. + (DISP_LR): Likewise. + + * term/i386/pc/console.c (pupa_console_putchar): New function. + 2003-02-08 NIIBE Yutaka * util/resolve.c (pupa_util_resolve_dependencies): BUG diff --git a/conf/i386-pc.mk b/conf/i386-pc.mk index a44441bfd..25b52fbe3 100644 --- a/conf/i386-pc.mk +++ b/conf/i386-pc.mk @@ -223,7 +223,7 @@ kernel_img_HEADERS = boot.h device.h disk.h dl.h elf.h err.h \ file.h fs.h kernel.h loader.h misc.h mm.h net.h rescue.h symbol.h \ term.h types.h machine/biosdisk.h machine/boot.h \ machine/console.h machine/init.h machine/memory.h \ - machine/loader.h machine/partition.h + machine/loader.h machine/partition.h machine/vga.h kernel_img_CFLAGS = $(COMMON_CFLAGS) kernel_img_ASFLAGS = $(COMMON_ASFLAGS) kernel_img_LDFLAGS = -nostdlib -Wl,-N,-Ttext,8200 @@ -394,7 +394,8 @@ genmoddep-util_genmoddep.d: util/genmoddep.c # Modules. -pkgdata_MODULES = _chain.mod _linux.mod fat.mod normal.mod +pkgdata_MODULES = _chain.mod _linux.mod fat.mod normal.mod hello.mod \ + vga.mod font.mod # For _chain.mod. _chain_mod_SOURCES = loader/i386/pc/chainloader.c @@ -585,6 +586,123 @@ normal_mod-normal_i386_setjmp.d: normal/i386/setjmp.S normal_mod_CFLAGS = $(COMMON_CFLAGS) normal_mod_ASFLAGS = $(COMMON_ASFLAGS) + +# For hello.mod. +hello_mod_SOURCES = hello/hello.c +CLEANFILES += hello.mod mod-hello.o mod-hello.c pre-hello.o hello_mod-hello_hello.o def-hello.lst und-hello.lst +MOSTLYCLEANFILES += hello_mod-hello_hello.d +DEFSYMFILES += def-hello.lst +UNDSYMFILES += und-hello.lst + +hello.mod: pre-hello.o mod-hello.o + -rm -f $@ + $(LD) -r -o $@ $^ + $(STRIP) --strip-unneeded -K pupa_mod_init -K pupa_mod_fini -R .note -R .comment $@ + +pre-hello.o: hello_mod-hello_hello.o + -rm -f $@ + $(LD) -r -o $@ $^ + +mod-hello.o: mod-hello.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(hello_mod_CFLAGS) -c -o $@ $< + +mod-hello.c: moddep.lst genmodsrc.sh + sh $(srcdir)/genmodsrc.sh 'hello' $< > $@ || (rm -f $@; exit 1) + +def-hello.lst: pre-hello.o + $(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 hello/' > $@ + +und-hello.lst: pre-hello.o + echo 'hello' > $@ + $(NM) -u -P -p $< >> $@ + +hello_mod-hello_hello.o: hello/hello.c + $(CC) -Ihello -I$(srcdir)/hello $(CPPFLAGS) $(CFLAGS) $(hello_mod_CFLAGS) -c -o $@ $< + +hello_mod-hello_hello.d: hello/hello.c + set -e; $(CC) -Ihello -I$(srcdir)/hello $(CPPFLAGS) $(CFLAGS) $(hello_mod_CFLAGS) -M $< | sed 's,hello\.o[ :]*,hello_mod-hello_hello.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include hello_mod-hello_hello.d + +hello_mod_CFLAGS = $(COMMON_CFLAGS) + +# For vga.mod. +vga_mod_SOURCES = term/i386/pc/vga.c +CLEANFILES += vga.mod mod-vga.o mod-vga.c pre-vga.o vga_mod-term_i386_pc_vga.o def-vga.lst und-vga.lst +MOSTLYCLEANFILES += vga_mod-term_i386_pc_vga.d +DEFSYMFILES += def-vga.lst +UNDSYMFILES += und-vga.lst + +vga.mod: pre-vga.o mod-vga.o + -rm -f $@ + $(LD) -r -o $@ $^ + $(STRIP) --strip-unneeded -K pupa_mod_init -K pupa_mod_fini -R .note -R .comment $@ + +pre-vga.o: vga_mod-term_i386_pc_vga.o + -rm -f $@ + $(LD) -r -o $@ $^ + +mod-vga.o: mod-vga.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(vga_mod_CFLAGS) -c -o $@ $< + +mod-vga.c: moddep.lst genmodsrc.sh + sh $(srcdir)/genmodsrc.sh 'vga' $< > $@ || (rm -f $@; exit 1) + +def-vga.lst: pre-vga.o + $(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 vga/' > $@ + +und-vga.lst: pre-vga.o + echo 'vga' > $@ + $(NM) -u -P -p $< >> $@ + +vga_mod-term_i386_pc_vga.o: term/i386/pc/vga.c + $(CC) -Iterm/i386/pc -I$(srcdir)/term/i386/pc $(CPPFLAGS) $(CFLAGS) $(vga_mod_CFLAGS) -c -o $@ $< + +vga_mod-term_i386_pc_vga.d: term/i386/pc/vga.c + set -e; $(CC) -Iterm/i386/pc -I$(srcdir)/term/i386/pc $(CPPFLAGS) $(CFLAGS) $(vga_mod_CFLAGS) -M $< | sed 's,vga\.o[ :]*,vga_mod-term_i386_pc_vga.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include vga_mod-term_i386_pc_vga.d + +vga_mod_CFLAGS = $(COMMON_CFLAGS) + +# For font.mod. +font_mod_SOURCES = font/manager.c +CLEANFILES += font.mod mod-font.o mod-font.c pre-font.o font_mod-font_manager.o def-font.lst und-font.lst +MOSTLYCLEANFILES += font_mod-font_manager.d +DEFSYMFILES += def-font.lst +UNDSYMFILES += und-font.lst + +font.mod: pre-font.o mod-font.o + -rm -f $@ + $(LD) -r -o $@ $^ + $(STRIP) --strip-unneeded -K pupa_mod_init -K pupa_mod_fini -R .note -R .comment $@ + +pre-font.o: font_mod-font_manager.o + -rm -f $@ + $(LD) -r -o $@ $^ + +mod-font.o: mod-font.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(font_mod_CFLAGS) -c -o $@ $< + +mod-font.c: moddep.lst genmodsrc.sh + sh $(srcdir)/genmodsrc.sh 'font' $< > $@ || (rm -f $@; exit 1) + +def-font.lst: pre-font.o + $(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 font/' > $@ + +und-font.lst: pre-font.o + echo 'font' > $@ + $(NM) -u -P -p $< >> $@ + +font_mod-font_manager.o: font/manager.c + $(CC) -Ifont -I$(srcdir)/font $(CPPFLAGS) $(CFLAGS) $(font_mod_CFLAGS) -c -o $@ $< + +font_mod-font_manager.d: font/manager.c + set -e; $(CC) -Ifont -I$(srcdir)/font $(CPPFLAGS) $(CFLAGS) $(font_mod_CFLAGS) -M $< | sed 's,manager\.o[ :]*,font_mod-font_manager.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include font_mod-font_manager.d + +font_mod_CFLAGS = $(COMMON_CFLAGS) CLEANFILES += moddep.lst pkgdata_DATA += moddep.lst moddep.lst: $(DEFSYMFILES) $(UNDSYMFILES) genmoddep diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index 1d49d686e..e2484b44a 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -28,7 +28,7 @@ kernel_img_HEADERS = boot.h device.h disk.h dl.h elf.h err.h \ file.h fs.h kernel.h loader.h misc.h mm.h net.h rescue.h symbol.h \ term.h types.h machine/biosdisk.h machine/boot.h \ machine/console.h machine/init.h machine/memory.h \ - machine/loader.h machine/partition.h + machine/loader.h machine/partition.h machine/vga.h kernel_img_CFLAGS = $(COMMON_CFLAGS) kernel_img_ASFLAGS = $(COMMON_ASFLAGS) kernel_img_LDFLAGS = -nostdlib -Wl,-N,-Ttext,8200 @@ -61,7 +61,8 @@ pupa_setup_SOURCES = util/i386/pc/pupa-setup.c util/i386/pc/biosdisk.c \ genmoddep_SOURCES = util/genmoddep.c # Modules. -pkgdata_MODULES = _chain.mod _linux.mod fat.mod normal.mod hello.mod +pkgdata_MODULES = _chain.mod _linux.mod fat.mod normal.mod hello.mod \ + vga.mod font.mod # For _chain.mod. _chain_mod_SOURCES = loader/i386/pc/chainloader.c @@ -84,3 +85,11 @@ normal_mod_ASFLAGS = $(COMMON_ASFLAGS) # For hello.mod. hello_mod_SOURCES = hello/hello.c hello_mod_CFLAGS = $(COMMON_CFLAGS) + +# For vga.mod. +vga_mod_SOURCES = term/i386/pc/vga.c +vga_mod_CFLAGS = $(COMMON_CFLAGS) + +# For font.mod. +font_mod_SOURCES = font/manager.c +font_mod_CFLAGS = $(COMMON_CFLAGS) diff --git a/font/manager.c b/font/manager.c new file mode 100644 index 000000000..77c682285 --- /dev/null +++ b/font/manager.c @@ -0,0 +1,243 @@ +/* + * PUPA -- Preliminary Universal Programming Architecture for GRUB + * Copyright (C) 2003 Yoshinori K. Okuji + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +struct entry +{ + pupa_uint32_t code; + pupa_uint32_t offset; +}; + +struct font +{ + struct font *next; + pupa_file_t file; + pupa_uint32_t num; + struct entry table[0]; +}; + +static struct font *font_list; + +static int +add_font (const char *filename) +{ + pupa_file_t file = 0; + char magic[4]; + pupa_uint32_t num, i; + struct font *font = 0; + + file = pupa_file_open (filename); + if (! file) + goto fail; + + if (pupa_file_read (file, magic, 4) != 4) + goto fail; + + if (pupa_memcmp (magic, PUPA_FONT_MAGIC, 4) != 0) + { + pupa_error (PUPA_ERR_BAD_FONT, "invalid font magic"); + goto fail; + } + + if (pupa_file_read (file, (char *) &num, 4) != 4) + goto fail; + + num = pupa_le_to_cpu32 (num); + font = (struct font *) pupa_malloc (sizeof (struct font) + + sizeof (struct entry) * num); + if (! font) + goto fail; + + font->file = file; + font->num = num; + + for (i = 0; i < num; i++) + { + pupa_uint32_t code, offset; + + if (pupa_file_read (file, (char *) &code, 4) != 4) + goto fail; + + if (pupa_file_read (file, (char *) &offset, 4) != 4) + goto fail; + + font->table[i].code = pupa_le_to_cpu32 (code); + font->table[i].offset = pupa_le_to_cpu32 (offset); + } + + font->next = font_list; + font_list = font; + + return 1; + + fail: + if (font) + pupa_free (font); + + if (file) + pupa_file_close (file); + + return 0; +} + +static void +remove_font (struct font *font) +{ + struct font **p, *q; + + for (p = &font_list, q = *p; q; p = &(q->next), q = q->next) + if (q == font) + { + *p = q->next; + + pupa_file_close (font->file); + pupa_free (font); + + break; + } +} + +/* Return the offset of the glyph corresponding to the codepoint CODE + in the font FONT. If no found, return zero. */ +static pupa_uint32_t +find_glyph (const struct font *font, pupa_uint32_t code) +{ + pupa_uint32_t start = 0; + pupa_uint32_t end = font->num - 1; + struct entry *table = font->table; + + /* This shouldn't happen. */ + if (font->num == 0) + return 0; + + /* Do a binary search. */ + while (start <= end) + { + pupa_uint32_t i = (start + end) / 2; + + if (table[i].code < code) + start = i + 1; + else if (table[i].code > code) + end = i - 1; + else + return table[i].offset; + } + + return 0; +} + +/* Set the glyph to something stupid. */ +static void +fill_with_default_glyph (unsigned char bitmap[32], unsigned *width) +{ + if (bitmap) + { + unsigned i; + + for (i = 0; i < 16; i++) + bitmap[i] = (i & 1) ? 0x55 : 0xaa; + } + + *width = 1; +} + +/* Get a glyph corresponding to the codepoint CODE. Always fill BITMAP + and WIDTH with something, even if no glyph is found. */ +int +pupa_font_get_glyph (pupa_uint32_t code, + unsigned char bitmap[32], unsigned *width) +{ + struct font *font; + + /* FIXME: It is necessary to cache glyphs! */ + + restart: + for (font = font_list; font; font = font->next) + { + pupa_uint32_t offset; + + offset = find_glyph (font, code); + if (offset) + { + pupa_uint32_t w; + + pupa_file_seek (font->file, offset); + if (pupa_file_read (font->file, (char *) &w, 4) != 4) + { + remove_font (font); + goto restart; + } + + w = pupa_le_to_cpu32 (w); + if (w != 1 && w != 2) + { + /* pupa_error (PUPA_ERR_BAD_FONT, "invalid width"); */ + remove_font (font); + goto restart; + } + + if (bitmap + && (pupa_file_read (font->file, bitmap, w * 16) + != (pupa_ssize_t) w * 16)) + { + remove_font (font); + goto restart; + } + + *width = w; + return 1; + } + } + + /* Uggh... No font was found. */ + fill_with_default_glyph (bitmap, width); + return 0; +} + +static int +font_command (int argc, char *argv[]) +{ + if (argc == 0) + return pupa_error (PUPA_ERR_BAD_ARGUMENT, "no font specified"); + + while (argc--) + if (! add_font (*argv++)) + return 1; + + return 0; +} + +PUPA_MOD_INIT +{ + pupa_register_command ("font", font_command, PUPA_COMMAND_FLAG_BOTH, + "font FILE...", + "Specify a font file to display."); +} + +PUPA_MOD_FINI +{ + pupa_unregister_command ("font"); +} diff --git a/include/grub/err.h b/include/grub/err.h index 33bcf6d30..9cdc5175d 100644 --- a/include/grub/err.h +++ b/include/grub/err.h @@ -46,6 +46,7 @@ typedef enum PUPA_ERR_UNKNOWN_OS, PUPA_ERR_BAD_OS, PUPA_ERR_NO_KERNEL, + PUPA_ERR_BAD_FONT, PUPA_ERR_NOT_IMPLEMENTED_YET, } pupa_err_t; diff --git a/include/grub/font.h b/include/grub/font.h new file mode 100644 index 000000000..a866ceee2 --- /dev/null +++ b/include/grub/font.h @@ -0,0 +1,30 @@ +/* + * PUPA -- Preliminary Universal Programming Architecture for GRUB + * Copyright (C) 2003 Yoshinori K. Okuji + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef PUPA_FONT_HEADER +#define PUPA_FONT_HEADER 1 + +#include + +#define PUPA_FONT_MAGIC "PPF\x7f" + +int pupa_font_get_glyph (pupa_uint32_t code, + unsigned char bitmap[32], unsigned *width); + +#endif /* ! PUPA_FONT_HEADER */ diff --git a/include/grub/i386/pc/console.h b/include/grub/i386/pc/console.h index 69601e5d5..8a846b4b0 100644 --- a/include/grub/i386/pc/console.h +++ b/include/grub/i386/pc/console.h @@ -36,12 +36,13 @@ #ifndef ASM_FILE #include +#include /* These are global to share code between C and asm. */ extern pupa_uint8_t pupa_console_cur_color; -void pupa_console_putchar (int c); -int pupa_console_checkkey (void); -int pupa_console_getkey (void); +void pupa_console_real_putchar (int c); +int EXPORT_FUNC(pupa_console_checkkey) (void); +int EXPORT_FUNC(pupa_console_getkey) (void); pupa_uint16_t pupa_console_getxy (void); void pupa_console_gotoxy (pupa_uint8_t x, pupa_uint8_t y); void pupa_console_cls (void); diff --git a/include/grub/i386/pc/vga.h b/include/grub/i386/pc/vga.h new file mode 100644 index 000000000..013e377b3 --- /dev/null +++ b/include/grub/i386/pc/vga.h @@ -0,0 +1,31 @@ +/* + * PUPA -- Preliminary Universal Programming Architecture for GRUB + * Copyright (C) 2003 Yoshinori K. Okuji + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef PUPA_VGA_MACHINE_HEADER +#define PUPA_VGA_MACHINE_HEADER 1 + +#include + +/* Set the video mode to MODE and return the previous mode. */ +unsigned char EXPORT_FUNC(pupa_vga_set_mode) (unsigned char mode); + +/* Return a pointer to the ROM font table. */ +unsigned char *EXPORT_FUNC(pupa_vga_get_font) (void); + +#endif /* ! PUPA_VGA_MACHINE_HEADER */ diff --git a/include/grub/term.h b/include/grub/term.h index 87b285dec..4c40a2f86 100644 --- a/include/grub/term.h +++ b/include/grub/term.h @@ -1,7 +1,7 @@ /* * PUPA -- Preliminary Universal Programming Architecture for GRUB - * Copyright (C) 2002 Free Software Foundation, Inc. - * Copyright (C) 2002 Yoshinori K. Okuji + * Copyright (C) 2002 Free Software Foundation, Inc. + * Copyright (C) 2002,2003 Yoshinori K. Okuji * * PUPA is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,6 +21,7 @@ #ifndef PUPA_TERM_HEADER #define PUPA_TERM_HEADER 1 +#include #include #include @@ -59,9 +60,15 @@ struct pupa_term { /* The terminal name. */ const char *name; + + /* Initialize the terminal. */ + pupa_err_t (*init) (void); + + /* Clean up the terminal. */ + pupa_err_t (*fini) (void); - /* Put a character. */ - void (*putchar) (int c); + /* Put a character. C is encoded in Unicode. */ + void (*putchar) (pupa_uint32_t c); /* Check if any input character is available. */ int (*checkkey) (void); @@ -100,10 +107,11 @@ void EXPORT_FUNC(pupa_term_register) (pupa_term_t term); void EXPORT_FUNC(pupa_term_unregister) (pupa_term_t term); void EXPORT_FUNC(pupa_term_iterate) (int (*hook) (pupa_term_t term)); -void EXPORT_FUNC(pupa_term_set_current) (pupa_term_t term); +pupa_err_t EXPORT_FUNC(pupa_term_set_current) (pupa_term_t term); pupa_term_t EXPORT_FUNC(pupa_term_get_current) (void); void EXPORT_FUNC(pupa_putchar) (int c); +void EXPORT_FUNC(pupa_putcode) (pupa_uint32_t code); int EXPORT_FUNC(pupa_getkey) (void); int EXPORT_FUNC(pupa_checkkey) (void); pupa_uint16_t EXPORT_FUNC(pupa_getxy) (void); diff --git a/kern/i386/pc/startup.S b/kern/i386/pc/startup.S index da3f8668b..90c3ba3fb 100644 --- a/kern/i386/pc/startup.S +++ b/kern/i386/pc/startup.S @@ -1090,7 +1090,7 @@ xsmap: /* - * void pupa_console_putchar (int c) + * void pupa_console_real_putchar (int c) * * Put the character C on the console. Because GRUB wants to write a * character with an attribute, this implementation is a bit tricky. @@ -1103,7 +1103,7 @@ xsmap: * get the height of the screen, and the TELETYPE OUPUT BIOS call doesn't * support setting a background attribute. */ -FUNCTION(pupa_console_putchar) +FUNCTION(pupa_console_real_putchar) movl %eax, %edx pusha movb EXT_C(pupa_console_cur_color), %bl @@ -1514,3 +1514,60 @@ FUNCTION(pupa_currticks) popl %ebp ret + + +/* + * unsigned char pupa_vga_set_mode (unsigned char mode) + */ +FUNCTION(pupa_vga_set_mode) + pushl %ebp + pushl %ebx + movl %eax, %ecx + + call prot_to_real + .code16 + /* get current mode */ + xorw %bx, %bx + movb $0x0f, %ah + int $0x10 + movb %al, %dl + + /* set the new mode */ + movb %cl, %al + xorb %ah, %ah + int $0x10 + + DATA32 call real_to_prot + .code32 + + movb %dl, %al + popl %ebx + popl %ebp + ret + + +/* + * unsigned char *pupa_vga_get_font (void) + */ +FUNCTION(pupa_vga_get_font) + pushl %ebp + pushl %ebx + + call prot_to_real + .code16 + movw $0x1130, %ax + movb $0x06, %bh + int $0x10 + movw %es, %bx + movw %bp, %dx + DATA32 call real_to_prot + .code32 + + movzwl %bx, %ecx + shll $4, %ecx + movw %dx, %ax + addl %ecx, %eax + + popl %ebx + popl %ebp + ret diff --git a/kern/misc.c b/kern/misc.c index b765948f5..d3578d533 100644 --- a/kern/misc.c +++ b/kern/misc.c @@ -328,10 +328,10 @@ pupa_vsprintf (char *str, const char *fmt, va_list args) { char c; int count = 0; - auto void write_char (char ch); + auto void write_char (unsigned char ch); auto void write_str (const char *s); - void write_char (char ch) + void write_char (unsigned char ch) { if (str) *str++ = ch; @@ -375,7 +375,57 @@ pupa_vsprintf (char *str, const char *fmt, va_list args) case 'c': n = va_arg (args, int); - write_char (n); + write_char (n & 0xff); + break; + + case 'C': + { + pupa_uint32_t code = va_arg (args, pupa_uint32_t); + int shift; + unsigned mask; + + if (code <= 0x7f) + { + shift = 0; + mask = 0; + } + else if (code <= 0x7ff) + { + shift = 6; + mask = 0xc0; + } + else if (code <= 0xffff) + { + shift = 12; + mask = 0xe0; + } + else if (code <= 0x1fffff) + { + shift = 18; + mask = 0xf0; + } + else if (code <= 0x3ffffff) + { + shift = 24; + mask = 0xf8; + } + else if (code <= 0x7fffffff) + { + shift = 30; + mask = 0xfc; + } + else + { + code = '?'; + shift = 0; + mask = 0; + } + + write_char (mask | (code >> shift)); + + for (shift -= 6; shift >= 0; shift -= 6) + write_char (0x80 | (0x3f & (code >> shift))); + } break; case 's': diff --git a/kern/term.c b/kern/term.c index 6082e389a..1d605af2a 100644 --- a/kern/term.c +++ b/kern/term.c @@ -1,7 +1,7 @@ /* * PUPA -- Preliminary Universal Programming Architecture for GRUB - * Copyright (C) 2002 Free Software Foundation, Inc. - * Copyright (C) 2002 Yoshinori K. Okuji + * Copyright (C) 2002 Free Software Foundation, Inc. + * Copyright (C) 2002,2003 Yoshinori K. Okuji * * PUPA is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -58,10 +58,20 @@ pupa_term_iterate (int (*hook) (pupa_term_t term)) break; } -void +pupa_err_t pupa_term_set_current (pupa_term_t term) { + if (pupa_cur_term && pupa_cur_term->fini) + if ((pupa_cur_term->fini) () != PUPA_ERR_NONE) + return pupa_errno; + + if (term->init) + if ((term->init) () != PUPA_ERR_NONE) + return pupa_errno; + pupa_cur_term = term; + pupa_cls (); + return PUPA_ERR_NONE; } pupa_term_t @@ -70,24 +80,89 @@ pupa_term_get_current (void) return pupa_cur_term; } +/* Put a Unicode character. */ void -pupa_putchar (int c) +pupa_putcode (pupa_uint32_t code) { - if (c == '\t' && pupa_cur_term->getxy) + if (code == '\t' && pupa_cur_term->getxy) { int n; - + n = 8 - ((pupa_getxy () >> 8) & 7); while (n--) - pupa_putchar (' '); + pupa_putcode (' '); return; } - (pupa_cur_term->putchar) (c); + (pupa_cur_term->putchar) (code); - if (c == '\n') - pupa_putchar ('\r'); + if (code == '\n') + pupa_putcode ('\r'); +} + +/* Put a character. C is one byte of a UTF-8 stream. + This function gathers bytes until a valid Unicode character is found. */ +void +pupa_putchar (int c) +{ + static pupa_uint32_t code = 0; + static int count = 0; + + if (count) + { + if ((c & 0xc0) != 0x80) + { + /* invalid */ + code = '@'; + count = 0; + } + else + { + code <<= 6; + code |= (c & 0x3f); + count--; + } + } + else + { + if ((c & 0x80) == 0x00) + code = c; + else if ((c & 0xe0) == 0xc0) + { + count = 1; + code = c & 0x1f; + } + else if ((c & 0xf0) == 0xe0) + { + count = 2; + code = c & 0x0f; + } + else if ((c & 0xf8) == 0xf0) + { + count = 3; + code = c & 0x07; + } + else if ((c & 0xfc) == 0xf8) + { + count = 4; + code = c & 0x03; + } + else if ((c & 0xfe) == 0xfc) + { + count = 5; + code = c & 0x01; + } + else + /* invalid */ + code = '?'; + } + + if (count) + /* Not finished yet. */ + return; + + pupa_putcode (code); } int diff --git a/normal/command.c b/normal/command.c index ab148ae81..c1c125c46 100644 --- a/normal/command.c +++ b/normal/command.c @@ -21,6 +21,7 @@ #include #include #include +#include static pupa_command_t pupa_command_list; @@ -164,6 +165,51 @@ rescue_command (int argc __attribute__ ((unused)), return 0; } +static int +terminal_command (int argc, char *argv[]) +{ + pupa_term_t term = 0; + + auto int print_terminal (pupa_term_t); + auto int find_terminal (pupa_term_t); + + int print_terminal (pupa_term_t t) + { + pupa_printf (" %s", t->name); + return 0; + } + + int find_terminal (pupa_term_t t) + { + if (pupa_strcmp (t->name, argv[0]) == 0) + { + term = t; + return 1; + } + + return 0; + } + + if (argc == 0) + { + pupa_printf ("Available terminal(s):"); + pupa_term_iterate (print_terminal); + pupa_putchar ('\n'); + + pupa_printf ("Current terminal: %s\n", pupa_term_get_current ()->name); + } + else + { + pupa_term_iterate (find_terminal); + if (! term) + return pupa_error (PUPA_ERR_BAD_ARGUMENT, "no such terminal"); + + pupa_term_set_current (term); + } + + return PUPA_ERR_NONE; +} + void pupa_command_init (void) { @@ -173,4 +219,7 @@ pupa_command_init (void) pupa_register_command ("rescue", rescue_command, PUPA_COMMAND_FLAG_BOTH, "rescue", "Enter into the rescue mode."); + pupa_register_command ("terminal", terminal_command, PUPA_COMMAND_FLAG_BOTH, + "terminal [TERM...]", + "Select a terminal."); } diff --git a/normal/menu.c b/normal/menu.c index 65ab2934c..ac2e04391 100644 --- a/normal/menu.c +++ b/normal/menu.c @@ -23,15 +23,16 @@ /* FIXME: These below are all runaround. */ -#define DISP_UP 0x18 -#define DISP_DOWN 0x19 -#define DISP_RIGHT 0x1a -#define DISP_HLINE 0xc4 -#define DISP_VLINE 0xb3 -#define DISP_UL 0xda -#define DISP_UR 0xbf -#define DISP_LL 0xc0 -#define DISP_LR 0xd9 +#define DISP_LEFT 0x2190 +#define DISP_UP 0x2191 +#define DISP_RIGHT 0x2192 +#define DISP_DOWN 0x2193 +#define DISP_HLINE 0x2501 +#define DISP_VLINE 0x2503 +#define DISP_UL 0x250F +#define DISP_UR 0x2513 +#define DISP_LL 0x2517 +#define DISP_LR 0x251B static void draw_border (void) @@ -41,10 +42,10 @@ draw_border (void) pupa_setcolorstate (PUPA_TERM_COLOR_NORMAL); pupa_gotoxy (1, 3); - pupa_putchar (DISP_UL); + pupa_putcode (DISP_UL); for (i = 0; i < 73; i++) - pupa_putchar (DISP_HLINE); - pupa_putchar (DISP_UR); + pupa_putcode (DISP_HLINE); + pupa_putcode (DISP_UR); i = 1; while (1) @@ -54,17 +55,17 @@ draw_border (void) if (i > 12) break; - pupa_putchar (DISP_VLINE); + pupa_putcode (DISP_VLINE); pupa_gotoxy (75, 3 + i); - pupa_putchar (DISP_VLINE); + pupa_putcode (DISP_VLINE); i++; } - pupa_putchar (DISP_LL); + pupa_putcode (DISP_LL); for (i = 0; i < 73; i++) - pupa_putchar (DISP_HLINE); - pupa_putchar (DISP_LR); + pupa_putcode (DISP_HLINE); + pupa_putcode (DISP_LR); pupa_setcolorstate (PUPA_TERM_COLOR_STANDARD); } @@ -73,8 +74,8 @@ static void print_message (int nested) { pupa_printf ("\n\ - Use the %c and %c keys to select which entry is highlighted.\n", - DISP_UP, DISP_DOWN); + Use the %C and %C keys to select which entry is highlighted.\n", + (pupa_uint32_t) DISP_UP, (pupa_uint32_t) DISP_DOWN); pupa_printf ("\ Press enter to boot the selected OS, \'e\' to edit the\n\ commands before booting, or \'c\' for a command-line."); @@ -113,7 +114,7 @@ print_entry (int y, int highlight, pupa_menu_entry_t entry) if (*title && x <= 72) { if (x == 72) - pupa_putchar (DISP_RIGHT); + pupa_putcode (DISP_RIGHT); else pupa_putchar (*title++); } @@ -134,7 +135,7 @@ print_entries (pupa_menu_t menu, int first, int offset) pupa_gotoxy (77, 4); if (first) - pupa_putchar (DISP_UP); + pupa_putcode (DISP_UP); else pupa_putchar (' '); @@ -150,7 +151,7 @@ print_entries (pupa_menu_t menu, int first, int offset) pupa_gotoxy (77, 4 + 12); if (e) - pupa_putchar (DISP_DOWN); + pupa_putcode (DISP_DOWN); else pupa_putchar (' '); diff --git a/term/i386/pc/console.c b/term/i386/pc/console.c index b0a3b8868..04cd7b083 100644 --- a/term/i386/pc/console.c +++ b/term/i386/pc/console.c @@ -1,7 +1,7 @@ /* * PUPA -- Preliminary Universal Programming Architecture for GRUB * Copyright (C) 2002 Free Software Foundation, Inc. - * Copyright (C) 2002 Yoshinori K. Okuji + * Copyright (C) 2002,2003 Yoshinori K. Okuji * * 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 @@ -27,6 +27,54 @@ static pupa_uint8_t pupa_console_standard_color = 0x7; static pupa_uint8_t pupa_console_normal_color = 0x7; static pupa_uint8_t pupa_console_highlight_color = 0x70; +static void +pupa_console_putchar (pupa_uint32_t c) +{ + if (c > 0x7f) + { + /* Map some unicode characters to the VGA font, if possible. */ + switch (c) + { + case 0x2190: /* left arrow */ + c = 0x1b; + break; + case 0x2191: /* up arrow */ + c = 0x18; + break; + case 0x2192: /* right arrow */ + c = 0x1a; + break; + case 0x2193: /* down arrow */ + c = 0x19; + break; + case 0x2501: /* horizontal line */ + c = 0xc4; + break; + case 0x2503: /* vertical line */ + c = 0xb3; + break; + case 0x250F: /* upper-left corner */ + c = 0xda; + break; + case 0x2513: /* upper-right corner */ + c = 0xbf; + break; + case 0x2517: /* lower-left corner */ + c = 0xc0; + break; + case 0x251B: /* lower-right corner */ + c = 0xd9; + break; + + default: + c = '?'; + break; + } + } + + pupa_console_real_putchar (c); +} + static void pupa_console_setcolorstate (pupa_term_color_state state) { @@ -55,6 +103,8 @@ pupa_console_setcolor (pupa_uint8_t normal_color, pupa_uint8_t highlight_color) static struct pupa_term pupa_console_term = { .name = "console", + .init = 0, + .fini = 0, .putchar = pupa_console_putchar, .checkkey = pupa_console_checkkey, .getkey = pupa_console_getkey, diff --git a/term/i386/pc/vga.c b/term/i386/pc/vga.c new file mode 100644 index 000000000..ef9b66525 --- /dev/null +++ b/term/i386/pc/vga.c @@ -0,0 +1,529 @@ +/* + * PUPA -- Preliminary Universal Programming Architecture for GRUB + * Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. + * Copyright (C) 2003 Yoshinori K. Okuji + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG_VGA 0 + +#define VGA_WIDTH 640 +#define VGA_HEIGHT 480 +#define CHAR_WIDTH 8 +#define CHAR_HEIGHT 16 +#define TEXT_WIDTH (VGA_WIDTH / CHAR_WIDTH) +#define TEXT_HEIGHT (VGA_HEIGHT / CHAR_HEIGHT) +#define VGA_MEM ((unsigned char *) 0xA0000) + +#define DEFAULT_FG_COLOR 0xa +#define DEFAULT_BG_COLOR 0x0 + +struct colored_char +{ + /* An Unicode codepoint. */ + pupa_uint32_t code; + + /* Color indexes. */ + unsigned char fg_color; + unsigned char bg_color; + + /* The width of this character minus one. */ + unsigned char width; + + /* The column index of this character. */ + unsigned char index; +}; + +static pupa_dl_t my_mod; +static unsigned char text_mode; +static unsigned xpos, ypos; +static int cursor_state; +static unsigned char fg_color, bg_color; +static struct colored_char text_buf[TEXT_WIDTH * TEXT_HEIGHT]; +static unsigned char *vga_font; +static unsigned char saved_map_mask; + +/* Read a byte from a port. */ +static inline unsigned char +inb (unsigned short port) +{ + unsigned char value; + + asm volatile ("inb %w1, %0" : "=a" (value) : "Nd" (port)); + asm volatile ("outb %%al, $0x80" : : ); + + return value; +} + +/* Write a byte to a port. */ +static inline void +outb (unsigned short port, unsigned char value) +{ + asm volatile ("outb %b0, %w1" : : "a" (value), "Nd" (port)); + asm volatile ("outb %%al, $0x80" : : ); +} + +#define SEQUENCER_ADDR_PORT 0x3C4 +#define SEQUENCER_DATA_PORT 0x3C5 +#define MAP_MASK_REGISTER 0x02 + +/* Get Map Mask Register. */ +static unsigned char +get_map_mask (void) +{ + unsigned char old_addr; + unsigned char old_data; + + old_addr = inb (SEQUENCER_ADDR_PORT); + outb (SEQUENCER_ADDR_PORT, MAP_MASK_REGISTER); + + old_data = inb (SEQUENCER_DATA_PORT); + + outb (SEQUENCER_ADDR_PORT, old_addr); + + return old_data; +} + +/* Set Map Mask Register. */ +static void +set_map_mask (unsigned char mask) +{ + unsigned char old_addr; + + old_addr = inb (SEQUENCER_ADDR_PORT); + outb (SEQUENCER_ADDR_PORT, MAP_MASK_REGISTER); + + outb (SEQUENCER_DATA_PORT, mask); + + outb (SEQUENCER_ADDR_PORT, old_addr); +} + +static pupa_err_t +pupa_vga_init (void) +{ + vga_font = pupa_vga_get_font (); + text_mode = pupa_vga_set_mode (0x12); + cursor_state = 1; + fg_color = DEFAULT_FG_COLOR; + bg_color = DEFAULT_BG_COLOR; + saved_map_mask = get_map_mask (); + set_map_mask (0x0f); + + return PUPA_ERR_NONE; +} + +static pupa_err_t +pupa_vga_fini (void) +{ + set_map_mask (saved_map_mask); + pupa_vga_set_mode (text_mode); + return PUPA_ERR_NONE; +} + +static int +get_vga_glyph (pupa_uint32_t code, unsigned char bitmap[32], unsigned *width) +{ + if (code > 0x7f) + { + /* Map some unicode characters to the VGA font, if possible. */ + switch (code) + { + case 0x2190: /* left arrow */ + code = 0x1b; + break; + case 0x2191: /* up arrow */ + code = 0x18; + break; + case 0x2192: /* right arrow */ + code = 0x1a; + break; + case 0x2193: /* down arrow */ + code = 0x19; + break; + case 0x2501: /* horizontal line */ + code = 0xc4; + break; + case 0x2503: /* vertical line */ + code = 0xb3; + break; + case 0x250F: /* upper-left corner */ + code = 0xda; + break; + case 0x2513: /* upper-right corner */ + code = 0xbf; + break; + case 0x2517: /* lower-left corner */ + code = 0xc0; + break; + case 0x251B: /* lower-right corner */ + code = 0xd9; + break; + + default: + return pupa_font_get_glyph (code, bitmap, width); + } + } + + if (bitmap) + pupa_memcpy (bitmap, vga_font + code * CHAR_HEIGHT, CHAR_HEIGHT); + + *width = 1; + return 1; +} + +static void +invalidate_char (struct colored_char *p) +{ + p->code = 0xFFFF; + + if (p->width) + { + struct colored_char *q; + + for (q = p + 1; q <= p + p->width; q++) + { + q->code = 0xFFFF; + q->width = 0; + q->index = 0; + } + } + + p->width = 0; +} + +static int +check_vga_mem (void *p) +{ + return p >= VGA_MEM && p <= VGA_MEM + VGA_WIDTH * VGA_HEIGHT / 8; +} + +static void +write_char (void) +{ + struct colored_char *p = text_buf + xpos + ypos * TEXT_WIDTH; + unsigned char bitmap[32]; + unsigned width; + unsigned char *mem_base = VGA_MEM + xpos + ypos * CHAR_HEIGHT * TEXT_WIDTH; + unsigned plane; + + mem_base -= p->index; + p -= p->index; + + if (! get_vga_glyph (p->code, bitmap, &width)) + invalidate_char (p); + + for (plane = 0x01; plane <= 0x08; plane <<= 1) + { + unsigned y; + unsigned offset; + unsigned char *mem; + + set_map_mask (plane); + + for (y = 0, offset = 0, mem = mem_base; + y < CHAR_HEIGHT; + y++, mem += TEXT_WIDTH) + { + unsigned i; + + for (i = 0; i < width && offset < 32; i++) + { + unsigned char fg_mask, bg_mask; + + fg_mask = (p->fg_color & plane) ? bitmap[offset] : 0; + bg_mask = (p->bg_color & plane) ? ~(bitmap[offset]) : 0; + offset++; + + if (check_vga_mem (mem + i)) + mem[i] = (fg_mask | bg_mask); + } + } + } + + set_map_mask (0x0f); +} + +static void +write_cursor (void) +{ + unsigned char *mem = (VGA_MEM + xpos + + (ypos * CHAR_HEIGHT + CHAR_HEIGHT - 3) * TEXT_WIDTH); + if (check_vga_mem (mem)) + *mem = 0xff; + + mem += TEXT_WIDTH; + if (check_vga_mem (mem)) + *mem = 0xff; +} + +static void +scroll_up (void) +{ + unsigned i; + unsigned plane; + + pupa_memmove (text_buf, text_buf + TEXT_WIDTH, + sizeof (struct colored_char) * TEXT_WIDTH * (TEXT_HEIGHT - 1)); + + for (i = TEXT_WIDTH * (TEXT_HEIGHT - 1); i < TEXT_WIDTH * TEXT_HEIGHT; i++) + { + text_buf[i].code = ' '; + text_buf[i].fg_color = 0; + text_buf[i].bg_color = 0; + text_buf[i].width = 0; + text_buf[i].index = 0; + } + + for (plane = 0x1; plane <= 0x8; plane <<= 1) + { + set_map_mask (plane); + pupa_memmove (VGA_MEM, VGA_MEM + VGA_WIDTH * CHAR_HEIGHT / 8, + VGA_WIDTH * (VGA_HEIGHT - CHAR_HEIGHT) / 8); + } + + set_map_mask (0x0f); + pupa_memset (VGA_MEM + VGA_WIDTH * (VGA_HEIGHT - CHAR_HEIGHT) / 8, 0, + VGA_WIDTH * CHAR_HEIGHT / 8); +} + +static void +pupa_vga_putchar (pupa_uint32_t c) +{ + static int show = 1; + + if (c == '\a') + /* FIXME */ + return; + + if (c == '\b' || c == '\n' || c == '\r') + { + /* Erase current cursor, if any. */ + if (cursor_state) + write_char (); + + switch (c) + { + case '\b': + if (xpos > 0) + xpos--; + break; + + case '\n': + if (ypos >= TEXT_HEIGHT) + scroll_up (); + else + ypos++; + break; + + case '\r': + xpos = 0; + break; + } + + if (cursor_state) + write_cursor (); + } + else + { + unsigned width; + struct colored_char *p; + + get_vga_glyph (c, 0, &width); + + if (xpos + width > TEXT_WIDTH) + pupa_putchar ('\n'); + + p = text_buf + xpos + ypos * TEXT_WIDTH; + p->code = c; + p->fg_color = fg_color; + p->bg_color = bg_color; + p->width = width - 1; + p->index = 0; + + if (width > 1) + { + unsigned i; + + for (i = 1; i < width; i++) + { + p[i].code = ' '; + p[i].width = width - 1; + p[i].index = i; + } + } + + write_char (); + + xpos += width; + if (xpos >= TEXT_WIDTH) + { + xpos = 0; + + if (ypos >= TEXT_HEIGHT) + scroll_up (); + else + ypos++; + } + + if (cursor_state) + write_cursor (); + } + +#if DEBUG_VGA + if (show) + { + pupa_uint16_t pos = pupa_getxy (); + + show = 0; + pupa_gotoxy (0, 0); + pupa_printf ("[%u:%u]", (unsigned) (pos >> 8), (unsigned) (pos & 0xff)); + pupa_gotoxy (pos >> 8, pos & 0xff); + show = 1; + } +#endif +} + + static pupa_uint16_t + pupa_vga_getxy (void) + { + return ((xpos << 8) | ypos); + } + + static void + pupa_vga_gotoxy (pupa_uint8_t x, pupa_uint8_t y) + { + if (x >= TEXT_WIDTH || y >= TEXT_HEIGHT) + { + pupa_error (PUPA_ERR_OUT_OF_RANGE, "invalid point (%u,%u)", + (unsigned) x, (unsigned) y); + return; + } + + if (cursor_state) + write_char (); + + xpos = x; + ypos = y; + + if (cursor_state) + write_cursor (); + } + + static void + pupa_vga_cls (void) + { + unsigned i; + + for (i = 0; i < TEXT_WIDTH * TEXT_HEIGHT; i++) + { + text_buf[i].code = ' '; + text_buf[i].fg_color = 0; + text_buf[i].bg_color = 0; + text_buf[i].width = 0; + text_buf[i].index = 0; + } + + pupa_memset (VGA_MEM, 0, VGA_WIDTH * VGA_HEIGHT / 8); + + xpos = ypos = 0; + } + + static void + pupa_vga_setcolorstate (pupa_term_color_state state) + { + switch (state) + { + case PUPA_TERM_COLOR_STANDARD: + case PUPA_TERM_COLOR_NORMAL: + fg_color = DEFAULT_FG_COLOR; + bg_color = DEFAULT_BG_COLOR; + break; + case PUPA_TERM_COLOR_HIGHLIGHT: + fg_color = DEFAULT_BG_COLOR; + bg_color = DEFAULT_FG_COLOR; + break; + default: + break; + } + } + + static void + pupa_vga_setcolor (pupa_uint8_t normal_color, pupa_uint8_t highlight_color) + { + /* FIXME */ + } + + static void + pupa_vga_setcursor (int on) + { + if (cursor_state != on) + { + if (cursor_state) + write_char (); + else + write_cursor (); + + cursor_state = on; + } + } + + static struct pupa_term pupa_vga_term = + { + .name = "vga", + .init = pupa_vga_init, + .fini = pupa_vga_fini, + .putchar = pupa_vga_putchar, + .checkkey = pupa_console_checkkey, + .getkey = pupa_console_getkey, + .getxy = pupa_vga_getxy, + .gotoxy = pupa_vga_gotoxy, + .cls = pupa_vga_cls, + .setcolorstate = pupa_vga_setcolorstate, + .setcolor = pupa_vga_setcolor, + .setcursor = pupa_vga_setcursor, + .flags = 0, + .next = 0 + }; + +static int +debug_command (int argc, char *argv[]) +{ + pupa_printf ("こんにちは\n"); + + return 0; +} + +PUPA_MOD_INIT +{ + my_mod = mod; + pupa_term_register (&pupa_vga_term); + pupa_register_command ("debug", debug_command, PUPA_COMMAND_FLAG_CMDLINE, + "debug", "Debug it!"); +} + +PUPA_MOD_FINI +{ + pupa_term_unregister (&pupa_vga_term); +} diff --git a/util/unifont2pff.rb b/util/unifont2pff.rb new file mode 100644 index 000000000..c2013cb07 --- /dev/null +++ b/util/unifont2pff.rb @@ -0,0 +1,79 @@ +#! /usr/bin/ruby -w +# +# Copyright (C) 2003 Yoshinori K. Okuji +# +# This unifont2pff.rb is free software; the author +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# The magic number of the font file. +MAGIC = "PPF\x7f" + +def usage(status = 0) + puts "Usage: ruby unifont2pff.rb [RANGE...] FILE" + exit(status) +end + +file = ARGV.pop + +ranges = [] +ARGV.each do |range| + if /\A([0-9a-fA-F]+):([0-9a-fA-F]+)\z/ =~ range + ranges << [$1.hex, $2.hex] + elsif /\A([0-9a-fA-F]+)\z/ =~ range + ranges << [$1.hex, $1.hex] + else + usage(1) + end +end + +def ranges.contain?(code) + if self.empty? + true + else + self.each do |r| + return true if r[0] <= code and r[1] >= code + end + false + end +end + +fonts = [] +IO.foreach(file) do |line| + if /^([0-9A-F]+):([0-9A-F]+)$/ =~ line + code = $1.hex + next unless ranges.contain?(code) + + bitmap = $2 + if bitmap.size != 32 and bitmap.size != 64 + raise "invalid bitmap size: #{bitmap}" + end + + fonts << [code, bitmap] + else + raise "invalid line format: #{line}" + end +end + +fonts.sort! {|a,b| a[0] <=> b[0]} + +# Output the result. +print MAGIC +print [fonts.size].pack('V') + +offset = 8 + fonts.size * 8 +fonts.each do |f| + print [f[0]].pack('V') + print [offset].pack('V') + offset += 4 + 16 * f[1].size / 32 +end + +fonts.each do |f| + print [f[1].size / 32].pack('V') + print f[1].scan(/../).collect {|a| a.hex}.pack('C*') +end