From: Matt Fleming Date: Tue, 18 Oct 2011 12:13:06 +0000 (+0100) Subject: core: Reimplement lots asm code in C X-Git-Tag: syslinux-5.00-pre1~35 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9f51b69d7c0500e04b3c404bb5138a9234810035;p=platform%2Fupstream%2Fsyslinux.git 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 --- 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(®, 0, sizeof(reg)); - reg.edi.w[0] = OFFS_WRT(KernelName, 0); - call16(core_open, ®, ®); - if (!(reg.eflags.l & EFLAGS_ZF)) - call16(get_msg_file, ®, 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(®, 0, sizeof(reg)); - reg.edi.w[0] = OFFS_WRT(KernelName, 0); - call16(core_open, ®, ®); - if (!(reg.eflags.l & EFLAGS_ZF)) - call16(loadfont, ®, 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(®, 0, sizeof(reg)); - reg.edi.w[0] = OFFS_WRT(KernelName, 0); - call16(core_open, ®, ®); - if (!(reg.eflags.l & EFLAGS_ZF)) - call16(loadkeys, ®, 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 or -; -abort_check: - call reset_idle ; Not idle despite pollchar - call pollchar - jz .ret1 - pusha - call getchar - cmp al,27 ; - je .kill - cmp al,3 ; - 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 +#include + +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 +#include +#include +#include + +#include +#include "bios.h" +#include +#include + +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) +{ + /* = 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 */ + break; + case 0x0A: /* = newline */ + msg_newline(); + break; + case 0x0C: /* = clear screen */ + msg_formfeed(); + break; + case 0x07: /* = beep */ + msg_beep(); + break; + case 0x19: /* = return to text mode */ + msg_novga(); + break; + case 0x18: /* = 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 - je msg_ignore - cmp al,0Ah ; = newline - je msg_newline - cmp al,0Ch ; = clear screen - je msg_formfeed - cmp al,07h ; = beep - je msg_beep - cmp al,19h ; = return to text mode - je msg_novga - cmp al,18h ; = 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 ; = 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 +#include +#include +#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 +#include "core.h" +#include +#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 +#include +#include +#include +#include + +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 +#include +#include +#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 +#include + +#include +#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 + +/* + * 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); +}