⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 l1.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 5 页
字号:
    /* uart interrupts were blocked at bedrock when the the interrupt     * was initially answered; reenable them now     */    intr_unblock_bit( sc->intr_cpu, UART_INTR );    ep = ep; /* placate the compiler */}#endif/* brl1_intr is called directly from the uart interrupt; after it runs, the * interrupt "daemon" xthread is signalled to continue. */#ifdef IRIXvoidbrl1_intr( struct eframe_s *ep ){    /* Disable the UART interrupt, giving the xthread time to respond.     * When the daemon (xthread) finishes doing its thing, it will     * unblock the interrupt.     */    intr_block_bit( get_elsc()->intr_cpu, UART_INTR );    ep = ep; /* placate the compiler */}/* set up uart interrupt handling for this node's uart */voidbrl1_connect_intr( l1sc_t *sc ){    cpuid_t last_cpu;    sc->intr_cpu = nodepda->node_first_cpu;    if( intr_connect_level(sc->intr_cpu, UART_INTR, INTPEND0_MAXMASK,			   (intr_func_t)brl1_intrd, 0, 			   (intr_func_t)brl1_intr) )	cmn_err(CE_PANIC, "brl1_connect_intr: Can't connect UART interrupt.");    uart_enable_recv_intr( sc );}#endif	/* IRIX */#ifdef SABLE/* this function is called periodically to generate fake interrupts * and allow brl1_intrd to send/receive characters */voidhubuart_service( void ){    l1sc_t *sc = get_elsc();    /* note that we'll lose error state by reading the lsr_reg.     * This is probably ok in the frictionless domain of sable.     */    int lsr_reg;    nasid_t nasid = sc->nasid;    lsr_reg = READ_L1_UART_REG( nasid, REG_LSR );    if( lsr_reg & (LSR_RCA | LSR_XSRE) ) {        REMOTE_HUB_PI_SEND_INTR(0, 0, UART_INTR);    }}#endif /* SABLE *//********************************************************************* * The following function allows the kernel to "go around" the * uninitialized l1sc structure to allow console output during * early system startup. *//* These are functions to use from serial_in/out when in protocol * mode to send and receive uart control regs. */voidbrl1_send_control(int offset, int value){	nasid_t nasid = get_nasid();	WRITE_L1_UART_REG(nasid, offset, value); }intbrl1_get_control(int offset){	nasid_t nasid = get_nasid();	return(READ_L1_UART_REG(nasid, offset)); }#define PUTCHAR(ch) \    { \        while( !(READ_L1_UART_REG( nasid, REG_LSR ) & LSR_XHRE) );  \        WRITE_L1_UART_REG( nasid, REG_DAT, (ch) ); \    }intbrl1_send_console_packet( char *str, int len ){    int sent = len;    char crc_char;    unsigned short crc = INIT_CRC;    nasid_t nasid = get_nasid();    PUTCHAR( BRL1_FLAG_CH );    PUTCHAR( BRL1_EVENT | SC_CONS_SYSTEM );    crc = crc16_calc( crc, (BRL1_EVENT | SC_CONS_SYSTEM) );    while( len ) {	if( (*str == BRL1_FLAG_CH) || (*str == BRL1_ESC_CH) ) {	    PUTCHAR( BRL1_ESC_CH );	    PUTCHAR( (*str) ^ BRL1_XOR_CH );	}	else {	    PUTCHAR( *str );	}		crc = crc16_calc( crc, *str );	str++; len--;    }        crc ^= 0xffff;    crc_char = crc & 0xff;    if( (crc_char == BRL1_ESC_CH) || (crc_char == BRL1_FLAG_CH) ) {	crc_char ^= BRL1_XOR_CH;	PUTCHAR( BRL1_ESC_CH );    }    PUTCHAR( crc_char );    crc_char = (crc >> 8) & 0xff;    if( (crc_char == BRL1_ESC_CH) || (crc_char == BRL1_FLAG_CH) ) {	crc_char ^= BRL1_XOR_CH;	PUTCHAR( BRL1_ESC_CH );    }    PUTCHAR( crc_char );    PUTCHAR( BRL1_FLAG_CH );    return sent - len;}/********************************************************************* * l1_cons functions * * These allow the L1 to act as the system console.  They're intended * to abstract away most of the br/l1 internal details from the * _L1_cons_* functions (in the prom-- see "l1_console.c") and * l1_* functions (in the kernel-- see "sio_l1.c") that they support. * */intl1_cons_poll( l1sc_t *sc ){    /* in case this gets called before the l1sc_t structure for the module_t     * struct for this node is initialized (i.e., if we're called with a     * zero l1sc_t pointer)...     */    if( !sc ) {	return 0;    }    if( sc->subch[SC_CONS_SYSTEM].packet_arrived ) {	return 1;    }    brl1_receive( sc );    if( sc->subch[SC_CONS_SYSTEM].packet_arrived ) {	return 1;    }    return 0;}/* pull a character off of the system console queue (if one is available) */intl1_cons_getc( l1sc_t *sc ){    int c;#ifdef SPINLOCKS_WORK    int pl;#endif    brl1_sch_t *subch = &(sc->subch[SC_CONS_SYSTEM]);    sc_cq_t *q = subch->iqp;    if( !l1_cons_poll( sc ) ) {	return 0;    }    SUBCH_DATA_LOCK( subch, pl );    if( cq_empty( q ) ) {	subch->packet_arrived = 0;	SUBCH_DATA_UNLOCK( subch, pl );	return 0;    }    cq_rem( q, c );    if( cq_empty( q ) )	subch->packet_arrived = 0;    SUBCH_DATA_UNLOCK( subch, pl );    return c;}/* initialize the system console subchannel */voidl1_cons_init( l1sc_t *sc ){#ifdef SPINLOCKS_WORK    int pl;#endif    brl1_sch_t *subch = &(sc->subch[SC_CONS_SYSTEM]);    SUBCH_DATA_LOCK( subch, pl );    subch->packet_arrived = 0;    cq_init( subch->iqp );    SUBCH_DATA_UNLOCK( subch, pl );}/* * Write a message to the L1 on the system console subchannel. * * Danger: don't use a non-zero value for the wait parameter unless you're * someone important (like a kernel error message). */intl1_cons_write( l1sc_t *sc, char *msg, int len, int wait ){    return( brl1_send( sc, msg, len, (SC_CONS_SYSTEM | BRL1_EVENT), wait ) );}/*  * Read as many characters from the system console receive queue as are * available there (up to avail bytes). */intl1_cons_read( l1sc_t *sc, char *buf, int avail ){    int pl;    int before_wrap, after_wrap;    brl1_sch_t *subch = &(sc->subch[SC_CONS_SYSTEM]);    sc_cq_t *q = subch->iqp;    if( !(subch->packet_arrived) )	return 0;    SUBCH_DATA_LOCK( subch, pl );    if( q->opos > q->ipos ) {	before_wrap = BRL1_QSIZE - q->opos;	if( before_wrap >= avail ) {	    before_wrap = avail;	    after_wrap = 0;	}	else {	    avail -= before_wrap;	    after_wrap = q->ipos;	    if( after_wrap > avail )		after_wrap = avail;	}    }    else {	before_wrap = q->ipos - q->opos;	if( before_wrap > avail )	    before_wrap = avail;	after_wrap = 0;    }    BCOPY( q->buf + q->opos, buf, before_wrap  );    if( after_wrap )        BCOPY( q->buf, buf + before_wrap, after_wrap  );    q->opos = ((q->opos + before_wrap + after_wrap) % BRL1_QSIZE);    subch->packet_arrived = 0;    SUBCH_DATA_UNLOCK( subch, pl );    return( before_wrap + after_wrap );}	/* * Install a callback function for the system console subchannel  * to allow an upper layer to be notified when the send buffer  * has been emptied. */voidl1_cons_tx_notif( l1sc_t *sc, brl1_notif_t func ){    subch_set_tx_notify( sc, SC_CONS_SYSTEM, func );}/* * Install a callback function for the system console subchannel * to allow an upper layer to be notified when a packet has been * received. */voidl1_cons_rx_notif( l1sc_t *sc, brl1_notif_t func ){    subch_set_rx_notify( sc, SC_CONS_SYSTEM, func );}/********************************************************************* * The following functions and definitions implement the "message"- * style interface to the L1 system controller. * * Note that throughout this file, "sc" generally stands for "system * controller", while "subchannels" tend to be represented by * variables with names like subch or ch. * */#ifdef L1_DEBUG#define L1_DBG_PRF(x) printf x#else#define L1_DBG_PRF(x)#endif/* sc_data_ready is called to signal threads that are blocked on  * l1 input. */voidsc_data_ready( l1sc_t *sc, int ch ){    brl1_sch_t *subch = &(sc->subch[ch]);    sv_signal( &(subch->arrive_sv) );}/* sc_open reserves a subchannel to send a request to the L1 (the * L1's response will arrive on the same channel).  The number * returned by sc_open is the system controller subchannel * acquired. */intsc_open( l1sc_t *sc, uint target ){    /* The kernel version implements a locking scheme to arbitrate     * subchannel assignment.     */    int ch;    int pl;    brl1_sch_t *subch;    SUBCH_LOCK( sc, pl );    /* Look for a free subchannel. Subchannels 0-15 are reserved     * for other purposes.     */    for( subch = &(sc->subch[BRL1_CMD_SUBCH]), ch = BRL1_CMD_SUBCH; 			ch < BRL1_NUM_SUBCHANS; subch++, ch++ ) {        if( subch->use == BRL1_SUBCH_FREE )            break;    }    if( ch == BRL1_NUM_SUBCHANS ) {        /* there were no subchannels available! */        SUBCH_UNLOCK( sc, pl );        return SC_NSUBCH;    }    subch->use = BRL1_SUBCH_RSVD;    SUBCH_UNLOCK( sc, pl );    subch->packet_arrived = 0;    subch->target = target;    sv_init( &(subch->arrive_sv), SV_FIFO, NULL );    spinlock_init( &(subch->data_lock), NULL );    subch->tx_notify = NULL;    subch->rx_notify = sc_data_ready;    subch->iqp = kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP,				   NASID_TO_COMPACT_NODEID(sc->nasid) );    ASSERT( subch->iqp );    cq_init( subch->iqp );    return ch;}/* sc_close frees a Bedrock<->L1 subchannel. */intsc_close( l1sc_t *sc, int ch ){    brl1_sch_t *subch;    int pl;    SUBCH_LOCK( sc, pl );    subch = &(sc->subch[ch]);    if( subch->use != BRL1_SUBCH_RSVD ) {        /* we're trying to close a subchannel that's not open */        return SC_NOPEN;    }    subch->packet_arrived = 0;    subch->use = BRL1_SUBCH_FREE;    sv_broadcast( &(subch->arrive_sv) );    sv_destroy( &(subch->arrive_sv) );    spinlock_destroy( &(subch->data_lock) );    ASSERT( subch->iqp && (subch->iqp != &sc->garbage_q) );    kmem_free( subch->iqp, sizeof(sc_cq_t) );    subch->iqp = &sc->garbage_q;    SUBCH_UNLOCK( sc, pl );    return SC_SUCCESS;}/* sc_construct_msg builds a bedrock-to-L1 request in the supplied * buffer.  Returns the length of the message.  The * safest course when passing a buffer to be filled in is to use * BRL1_QSIZE as the buffer size. * * Command arguments are passed as type/argument pairs, i.e., to * pass the number 5 as an argument to an L1 command, call * sc_construct_msg as follows: * *    char msg[BRL1_QSIZE]; *    msg_len = sc_construct_msg( msg, *				  BRL1_QSIZE, *				  target_component, *                                L1_ADDR_TASK_BOGUSTASK, *                                L1_BOGUSTASK_REQ_BOGUSREQ, *                                2, *                                L1_ARG_INT, 5 ); * * To pass an additional ASCII argument, you'd do the following: * *    char *str; *    ... str points to a null-terminated ascii string ... *    msg_len = sc_construct_msg( msg, *                                BRL1_QSIZE, *				  target_component, *                                L1_ADDR_TASK_BOGUSTASK, *                                L1_BOGUSTASK_REQ_BOGUSREQ, *                                4, *                                L1_ARG_INT, 5, *                                L1_ARG_ASCII, str ); * * Finally, arbitrary data of unknown type is passed using the argtype * code L1_ARG_UNKNOWN, a data length, and a buffer pointer, e.g. * *    msg_len = sc_construct_msg( msg, *                                BRL1_QSIZE, *				  target_component, *                                L1_ADDR_TASK_BOGUSTASK, *                                L1_BOGUSTASK_REQ_BOGUSREQ, *                                3, *                                L1_ARG_UNKNOWN, 32, bufptr ); * * ...passes 32 bytes of data starting at bufptr.  Note that no string or * "unknown"-type argument should be long enough to overflow the message * buffer. * * To construct a message for an L1 command that requires no arguments, * you'd use the following: * *    msg_len = sc_construct_msg( msg, *                                BRL1_QSIZE, *				  target_component, *                                L1_ADDR_TASK_BOGUSTASK, *                                L1_BOGUSTASK_REQ_BOGUSREQ, *                                0 ); * * The final 0 means "no varargs".  Notice that this parameter is used to hold * the number of additional arguments to sc_construct_msg, _not_ the actual * number of arguments used by the L1 command (so 2 per L1_ARG_[INT,ASCII] * type argument, and 3 per L1_ARG_UNKOWN type argument).  A call to construct * an L1 command which required three integer arguments and two arguments of * some arbitrary (unknown) type would pass 12 as the value for this parameter. * * ENDIANNESS WARNING: The following code does a lot of copying back-and-forth * between byte arrays and four-byte big-endian integers.  Depending on the * system controller connection and endianness of future architectures, some * rewriting might be necessary. */intsc_construct_msg( l1sc_t  *sc,		/* system controller struct */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -