diff --git a/kernel/arch/i386/Makefile.inc b/kernel/arch/i386/Makefile.inc index 5f4a96aa0..e40cde29f 100644 --- a/kernel/arch/i386/Makefile.inc +++ b/kernel/arch/i386/Makefile.inc @@ -14,6 +14,7 @@ SRCS+= arch_do_vmctl.c \ i8259.c \ klib.S \ memory.c \ + oxpcie.c \ protect.c \ arch_system.c \ apic.c \ diff --git a/kernel/arch/i386/arch_system.c b/kernel/arch/i386/arch_system.c index 1b9e45ef9..ac74007f7 100644 --- a/kernel/arch/i386/arch_system.c +++ b/kernel/arch/i386/arch_system.c @@ -14,6 +14,8 @@ #include "archconst.h" #include "proto.h" +#include "serial.h" +#include "oxpcie.h" #include "kernel/proc.h" #include "kernel/debug.h" @@ -220,18 +222,15 @@ PUBLIC void arch_init(void) fpu_init(); } -#define COM1_BASE 0x3F8 -#define COM1_THR (COM1_BASE + 0) -#define COM1_RBR (COM1_BASE + 0) -#define COM1_LSR (COM1_BASE + 5) -#define LSR_DR 0x01 -#define LSR_THRE 0x20 - PUBLIC void ser_putc(char c) { int i; int lsr, thr; +#if CONFIG_OXPCIE + oxpcie_putc(c); +#endif + lsr= COM1_LSR; thr= COM1_THR; for (i= 0; i<100000; i++) @@ -249,6 +248,14 @@ PUBLIC void do_ser_debug() { u8_t c, lsr; +#if CONFIG_OXPCIE + { + int oxin; + if((oxin = oxpcie_in()) >= 0) + ser_debug(oxin); + } +#endif + lsr= inb(COM1_LSR); if (!(lsr & LSR_DR)) return; diff --git a/kernel/arch/i386/memory.c b/kernel/arch/i386/memory.c index b4c6111ad..e3bc551be 100644 --- a/kernel/arch/i386/memory.c +++ b/kernel/arch/i386/memory.c @@ -12,9 +12,11 @@ #include #include #include +#include #include +#include "oxpcie.h" #include "proto.h" #include "kernel/proto.h" #include "kernel/debug.h" @@ -935,32 +937,70 @@ void i386_freepde(const int pde) freepdes[nfreepdes++] = pde; } +PRIVATE int lapic_mapping_index = -1, oxpcie_mapping_index = -1; + PUBLIC int arch_phys_map(const int index, phys_bytes *addr, phys_bytes *len, int *flags) { + static int first = 1; + int freeidx = 0; + static char *ser_var = NULL; + + if(first) { +#ifdef CONFIG_APIC + if(lapic_addr) + lapic_mapping_index = freeidx++; +#endif + +#ifdef CONFIG_OXPCIE + if((ser_var = env_get("oxpcie"))) { + if(ser_var[0] != '0' || ser_var[1] != 'x') { + printf("oxpcie address in hex please\n"); + } else { + oxpcie_mapping_index = freeidx++; + } + } +#endif + first = 0; + } + #ifdef CONFIG_APIC /* map the local APIC if enabled */ - if (index == 0 && lapic_addr) { + if (index == lapic_mapping_index) { *addr = vir2phys(lapic_addr); *len = 4 << 10 /* 4kB */; *flags = VMMF_UNCACHED; return OK; } - return EINVAL; -#else - /* we don't want anything */ - return EINVAL; #endif + +#if CONFIG_OXPCIE + if(index == oxpcie_mapping_index) { + *addr = strtoul(ser_var+2, NULL, 16); + *len = 0x4000; + *flags = VMMF_UNCACHED; + return OK; + } +#endif + + return EINVAL; } PUBLIC int arch_phys_map_reply(const int index, const vir_bytes addr) { #ifdef CONFIG_APIC /* if local APIC is enabled */ - if (index == 0 && lapic_addr) { + if (index == lapic_mapping_index && lapic_addr) { lapic_addr_vaddr = addr; } #endif + +#if CONFIG_OXPCIE + if (index == oxpcie_mapping_index) { + oxpcie_set_vaddr((unsigned char *) addr); + } +#endif + return OK; } diff --git a/kernel/arch/i386/oxpcie.c b/kernel/arch/i386/oxpcie.c new file mode 100644 index 000000000..67c8cd062 --- /dev/null +++ b/kernel/arch/i386/oxpcie.c @@ -0,0 +1,83 @@ + +#include "kernel/kernel.h" + +#if CONFIG_OXPCIE + +/* Documentation is at http://www.plxtech.com/products/uart/oxpcie952 */ + +#include "oxpcie.h" +#include "serial.h" + +PRIVATE unsigned char *oxpcie_vaddr = NULL; + +PUBLIC void oxpcie_set_vaddr(unsigned char *vaddr) +{ + oxpcie_vaddr = vaddr; +} + +PRIVATE void oxpcie_init(void) +{ + printf("oxpcie_init\n"); + /* Enable access to EFR and DLM+DLL */ + OXPCIE_LCR = 0xBF; + + /* Set FICR[1] to increase FIFO */ + OXPCIE_FICR = 0x01; + + /* Set enhanced mode [4] + * no RTS/CTS [7:6] + * no special char detection [5] + * no in-band receive flow control [1:0] + * no in-band transmit flow control [3:2] + */ + OXPCIE_EFR = 0x10; + + /* Set divisor register to 115200 baud. */ + OXPCIE_DLM = 0x00; + OXPCIE_DLL = 0x22; + + /* Forget DLM and DLL, set LCR to config. */ + OXPCIE_LCR = LCR_CONFIG; + OXPCIE_LCR = LCR_CONFIG; + + OXPCIE_TCR = 0x01; + OXPCIE_CPR = 0x20; + OXPCIE_CPR2 = 0; +} + +PUBLIC void oxpcie_putc(char c) +{ + static int inuse = 0; + + if(vm_running && oxpcie_vaddr && !inuse) { + int i; + static int init_done; + inuse = 1; + + if(!init_done) { + oxpcie_init(); + init_done = 1; + } + + for (i= 0; i<100000; i++) { + if(OXPCIE_LSR & LSR_THRE) + break; + } + OXPCIE_THR = c; + inuse = 0; + } +} + +PUBLIC int oxpcie_in(void) +{ + if(vm_running && oxpcie_vaddr) { + int lsr; + lsr = OXPCIE_LSR; + if(lsr & LSR_DR) + return (int) OXPCIE_RBR; + } + + return -1; +} + +#endif diff --git a/kernel/arch/i386/oxpcie.h b/kernel/arch/i386/oxpcie.h new file mode 100644 index 000000000..7ac39b390 --- /dev/null +++ b/kernel/arch/i386/oxpcie.h @@ -0,0 +1,31 @@ + +_PROTOTYPE( void oxpcie_set_vaddr, (unsigned char *vaddr)); +_PROTOTYPE( void oxpcie_putc, (char c)); +_PROTOTYPE( int oxpcie_in, (void)); + +#include "serial.h" + +/* OXPCIe952 info */ +#define UART1BASE_550 0x1000 +#define UART1BASE_650 0x1090 +#define UART1BASE_950 +#define BASELINEICR (UART1BASE_550 + 0xC0) +#define OXPCIE_THR oxpcie_vaddr[UART1BASE_550 + THRREG] +#define OXPCIE_RBR oxpcie_vaddr[UART1BASE_550 + RBRREG] +#define OXPCIE_LSR oxpcie_vaddr[UART1BASE_550 + LSRREG] +#define OXPCIE_LCR oxpcie_vaddr[UART1BASE_550 + LCRREG] +#define OXPCIE_DLL oxpcie_vaddr[UART1BASE_550 + 0x00] +#define OXPCIE_DLM oxpcie_vaddr[UART1BASE_550 + 0x01] +#define OXPCIE_FICR oxpcie_vaddr[UART1BASE_550 + FICRREG] +#define OXPCIE_SPR oxpcie_vaddr[UART1BASE_550 + SPRREG] +#define OXPCIE_EFR oxpcie_vaddr[UART1BASE_650 + 0x10] +#define OXPCIE_ICR oxpcie_vaddr[UART1BASE_950 + 0x05] + +#define OXPCIE_CPR oxpcie_vaddr[BASELINEICR + 0x01] +#define OXPCIE_TCR oxpcie_vaddr[BASELINEICR + 0x02] +#define OXPCIE_CPR2 oxpcie_vaddr[BASELINEICR + 0x03] +#define OXPCIE_CSR oxpcie_vaddr[BASELINEICR + 0x0C] +#define OXPCIE_PIDX oxpcie_vaddr[BASELINEICR + 0x12] + +#define LCR_CONFIG 0x03 /* bits 6:0 -= 0x03 => 8N1, no break. */ + diff --git a/kernel/arch/i386/serial.h b/kernel/arch/i386/serial.h new file mode 100644 index 000000000..230fd8519 --- /dev/null +++ b/kernel/arch/i386/serial.h @@ -0,0 +1,20 @@ + +#ifndef _KERN_SERIAL_H +#define _KERN_SERIAL_H 1 + +#define THRREG 0 +#define RBRREG 0 +#define FICRREG 2 +#define LSRREG 5 +#define LCRREG 3 +#define SPRREG 7 + +#define COM1_BASE 0x3F8 +#define COM1_THR (COM1_BASE + THRREG) +#define COM1_RBR (COM1_BASE + RBRREG) +#define COM1_LSR (COM1_BASE + LSRREG) +#define LSR_DR 0x01 +#define LSR_THRE 0x20 +#define LCR_DLA 0x80 + +#endif diff --git a/kernel/kernel.h b/kernel/kernel.h index b1ccf6097..6652a27c7 100644 --- a/kernel/kernel.h +++ b/kernel/kernel.h @@ -14,6 +14,9 @@ #define CONFIG_MAX_CPUS 1 #define cpuid 0 +/* OXPCIe952 PCIe with 2 UARTs in-kernel support */ +#define CONFIG_OXPCIE 0 + /* This is the master header for the kernel. It includes some other files * and defines the principal constants. */ diff --git a/kernel/proto.h b/kernel/proto.h index 0aa7e677d..38db7fbbc 100644 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -55,6 +55,7 @@ _PROTOTYPE( void check_ticks_left, (struct proc *p)); /* start.c */ _PROTOTYPE( void cstart, (u16_t cs, u16_t ds, u16_t mds, u16_t parmoff, u16_t parmsize) ); +_PROTOTYPE( char *env_get, (const char *key)); /* system.c */ _PROTOTYPE( int get_priv, (register struct proc *rc, int proc_type) ); diff --git a/kernel/start.c b/kernel/start.c index 68abd3121..3b4786309 100644 --- a/kernel/start.c +++ b/kernel/start.c @@ -11,7 +11,6 @@ #include "watchdog.h" #endif -FORWARD _PROTOTYPE( char *get_value, (const char *params, const char *key)); /*===========================================================================* * cstart * *===========================================================================*/ @@ -43,7 +42,7 @@ PUBLIC void cstart( arch_get_params(params_buffer, sizeof(params_buffer)); /* determine verbosity */ - if ((value = get_value(params_buffer, VERBOSEBOOTVARNAME))) + if ((value = env_get(VERBOSEBOOTVARNAME))) verboseboot = atoi(value); DEBUGEXTRA(("cstart\n")); @@ -63,10 +62,10 @@ PUBLIC void cstart( kloadinfo.proc_load_history[h] = 0; /* Processor? Decide if mode is protected for older machines. */ - machine.processor=atoi(get_value(params_buffer, "processor")); + machine.processor=atoi(env_get("processor")); /* XT, AT or MCA bus? */ - value = get_value(params_buffer, "bus"); + value = env_get("bus"); if (value == NULL || strcmp(value, "at") == 0) { machine.pc_at = TRUE; /* PC-AT compatible hardware */ } else if (strcmp(value, "mca") == 0) { @@ -74,22 +73,22 @@ PUBLIC void cstart( } /* Type of VDU: */ - value = get_value(params_buffer, "video"); /* EGA or VGA video unit */ + value = env_get("video"); /* EGA or VGA video unit */ if (strcmp(value, "ega") == 0) machine.vdu_ega = TRUE; if (strcmp(value, "vga") == 0) machine.vdu_vga = machine.vdu_ega = TRUE; /* Get clock tick frequency. */ - value = get_value(params_buffer, "hz"); + value = env_get("hz"); if(value) system_hz = atoi(value); if(!value || system_hz < 2 || system_hz > 50000) /* sanity check */ system_hz = DEFAULT_HZ; - value = get_value(params_buffer, SERVARNAME); + value = env_get(SERVARNAME); if(value && atoi(value) == 0) do_serial_debug=1; #ifdef CONFIG_APIC - value = get_value(params_buffer, "no_apic"); + value = env_get("no_apic"); if(value) config_no_apic = atoi(value); else @@ -97,7 +96,7 @@ PUBLIC void cstart( #endif #ifdef CONFIG_WATCHDOG - value = get_value(params_buffer, "watchdog"); + value = env_get("watchdog"); if (value) watchdog_enabled = atoi(value); #endif @@ -134,3 +133,12 @@ PRIVATE char *get_value( } return(NULL); } + +/*===========================================================================* + * env_get * + *===========================================================================*/ +PUBLIC char *env_get(const char *name) +{ + return get_value(params_buffer, name); +} +