Support for etherboot.
This commit is contained in:
parent
7c62dad87c
commit
9ea31ee45a
21 changed files with 4102 additions and 4 deletions
3
src/etherboot/Config
Normal file
3
src/etherboot/Config
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
object netboot.o
|
||||
object rarp.o
|
||||
object sis900.o
|
||||
173
src/etherboot/cards.h
Normal file
173
src/etherboot/cards.h
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
#ifndef CARDS_H
|
||||
#define CARDS_H
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2, or (at
|
||||
* your option) any later version.
|
||||
*/
|
||||
|
||||
#include "nic.h"
|
||||
|
||||
/* OK, this is how the PCI support hack works: if pci.h is included before
|
||||
* this file is included, assume that the driver supports PCI. This means that
|
||||
* this file is usually included last. */
|
||||
|
||||
#ifdef PCI_H
|
||||
#define PCI_ARG(x) ,x
|
||||
#else
|
||||
#define PCI_ARG(x)
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_WD
|
||||
extern struct nic *wd_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_3C503
|
||||
extern struct nic *t503_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_VIA_RHINE
|
||||
extern struct nic *rhine_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_NE
|
||||
extern struct nic *ne_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_NS8390
|
||||
extern struct nic *nepci_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_3C509
|
||||
extern struct nic *t509_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_3C529
|
||||
extern struct nic *t529_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_3C595
|
||||
extern struct nic *t595_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_3C90X
|
||||
extern struct nic *a3c90x_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_EEPRO
|
||||
extern struct nic *eepro_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_EEPRO100
|
||||
extern struct nic *eepro100_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_EPIC100
|
||||
extern struct nic *epic100_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_OTULIP
|
||||
extern struct nic *otulip_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_TULIP
|
||||
extern struct nic *tulip_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_DAVICOM
|
||||
extern struct nic *davicom_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_CS89X0
|
||||
extern struct nic *cs89x0_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_LANCE
|
||||
extern struct nic *lancepci_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_NE2100
|
||||
extern struct nic *ne2100_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_NI6510
|
||||
extern struct nic *ni6510_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_SK_G16
|
||||
extern struct nic *SK_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_3C507
|
||||
extern struct nic *t507_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_NI5010
|
||||
extern struct nic *ni5010_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_NI5210
|
||||
extern struct nic *ni5210_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_EXOS205
|
||||
extern struct nic *exos205_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_SMC9000
|
||||
extern struct nic *smc9000_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_TIARA
|
||||
extern struct nic *tiara_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_DEPCA
|
||||
extern struct nic *depca_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_RTL8139
|
||||
extern struct nic *rtl8139_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_W89C840
|
||||
extern struct nic *w89c840_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_SIS900
|
||||
extern struct nic *sis900_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
#endif /* CARDS_H */
|
||||
598
src/etherboot/etherboot.h
Normal file
598
src/etherboot/etherboot.h
Normal file
|
|
@ -0,0 +1,598 @@
|
|||
/**************************************************************************
|
||||
Etherboot - BOOTP/TFTP Bootstrap Program
|
||||
|
||||
Author: Martin Renters
|
||||
Date: Dec/93
|
||||
|
||||
**************************************************************************/
|
||||
|
||||
#include "osdep.h"
|
||||
|
||||
/* These could be customised for different languages perhaps */
|
||||
#define ASK_PROMPT "Boot from (N)etwork or from (L)ocal? "
|
||||
#define ANS_NETWORK 'N'
|
||||
#define ANS_LOCAL 'L'
|
||||
#ifndef ANS_DEFAULT /* in case left out in Makefile */
|
||||
#define ANS_DEFAULT ANS_NETWORK
|
||||
#endif
|
||||
|
||||
#if !defined(TAGGED_IMAGE) && !defined(AOUT_IMAGE) && !defined(ELF_IMAGE)
|
||||
#define TAGGED_IMAGE /* choose at least one */
|
||||
#endif
|
||||
|
||||
#define ESC '\033'
|
||||
|
||||
/* Edit this to change the path to hostspecific kernel image
|
||||
kernel.<client_ip_address> in RARP boot */
|
||||
#ifndef DEFAULT_KERNELPATH
|
||||
#define DEFAULT_KERNELPATH "/tftpboot/kernel.%I"
|
||||
#endif
|
||||
|
||||
/* Edit this to change the default fallback kernel image.
|
||||
This is used if bootp/dhcp-server doesn't provide the kernel path */
|
||||
#ifndef DEFAULT_BOOTFILE
|
||||
#define DEFAULT_BOOTFILE "/tftpboot/kernel"
|
||||
#endif
|
||||
|
||||
/* Clean up console settings... mainly CONSOLE_CRT and CONSOLE_SERIAL are used
|
||||
* in the sources (except start.S and serial.S which cannot include
|
||||
* etherboot.h). At least one of the CONSOLE_xxx has to be set, and
|
||||
* CONSOLE_DUAL sets both CONSOLE_CRT and CONSOLE_SERIAL. If none is set,
|
||||
* CONSOLE_CRT is assumed. */
|
||||
#ifdef CONSOLE_DUAL
|
||||
#undef CONSOLE_CRT
|
||||
#define CONSOLE_CRT
|
||||
#undef CONSOLE_SERIAL
|
||||
#define CONSOLE_SERIAL
|
||||
#endif
|
||||
#if defined(CONSOLE_CRT) && defined(CONSOLE_SERIAL)
|
||||
#undef CONSOLE_DUAL
|
||||
#define CONSOLE_DUAL
|
||||
#endif
|
||||
#if !defined(CONSOLE_CRT) && !defined(CONSOLE_SERIAL)
|
||||
#define CONSOLE_CRT
|
||||
#endif
|
||||
|
||||
#ifndef DOWNLOAD_PROTO_NFS
|
||||
#undef DOWNLOAD_PROTO_TFTP
|
||||
#define DOWNLOAD_PROTO_TFTP /* default booting protocol */
|
||||
#endif
|
||||
|
||||
#ifdef DOWNLOAD_PROTO_TFTP
|
||||
#define download(fname,loader) tftp((fname),(loader))
|
||||
#endif
|
||||
#ifdef DOWNLOAD_PROTO_NFS
|
||||
#define download(fname,loader) nfs((fname),(loader))
|
||||
#endif
|
||||
|
||||
#ifndef MAX_TFTP_RETRIES
|
||||
#define MAX_TFTP_RETRIES 20
|
||||
#endif
|
||||
|
||||
#ifndef MAX_BOOTP_RETRIES
|
||||
#define MAX_BOOTP_RETRIES 20
|
||||
#endif
|
||||
|
||||
#ifdef BOOTP_DATA_AT_0x93C00
|
||||
#define MAX_BOOTP_EXTLEN (1024-sizeof(struct bootp_t))
|
||||
#else
|
||||
#define MAX_BOOTP_EXTLEN (ETH_FRAME_LEN-ETH_HLEN-sizeof(struct bootp_t))
|
||||
#endif
|
||||
|
||||
#ifndef MAX_ARP_RETRIES
|
||||
#define MAX_ARP_RETRIES 20
|
||||
#endif
|
||||
|
||||
#ifndef MAX_RPC_RETRIES
|
||||
#define MAX_RPC_RETRIES 20
|
||||
#endif
|
||||
|
||||
#define TICKS_PER_SEC 18
|
||||
|
||||
/* Inter-packet retry in ticks */
|
||||
#define TIMEOUT (10*TICKS_PER_SEC)
|
||||
|
||||
/* These settings have sense only if compiled with -DCONGESTED */
|
||||
/* total retransmission timeout in ticks */
|
||||
#define TFTP_TIMEOUT (30*TICKS_PER_SEC)
|
||||
/* packet retransmission timeout in ticks */
|
||||
#define TFTP_REXMT (3*TICKS_PER_SEC)
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
I'm moving towards the defined names in linux/if_ether.h for clarity.
|
||||
The confusion between 60/64 and 1514/1518 arose because the NS8390
|
||||
counts the 4 byte frame checksum in the incoming packet, but not
|
||||
in the outgoing packet. 60/1514 are the correct numbers for most
|
||||
if not all of the other NIC controllers. I will be retiring the
|
||||
64/1518 defines in the lead-up to 5.0.
|
||||
*/
|
||||
|
||||
#define ETH_ALEN 6 /* Size of Ethernet address */
|
||||
#define ETH_HLEN 14 /* Size of ethernet header */
|
||||
#define ETH_ZLEN 60 /* Minimum packet */
|
||||
/*#define ETH_MIN_PACKET 64*/
|
||||
#define ETH_FRAME_LEN 1514 /* Maximum packet */
|
||||
/*#define ETH_MAX_PACKET 1518*/
|
||||
|
||||
#define ARP_CLIENT 0
|
||||
#define ARP_SERVER 1
|
||||
#define ARP_GATEWAY 2
|
||||
#define ARP_ROOTSERVER 3
|
||||
#define ARP_SWAPSERVER 4
|
||||
#define MAX_ARP ARP_SWAPSERVER+1
|
||||
|
||||
#define RARP_REQUEST 3
|
||||
#define RARP_REPLY 4
|
||||
|
||||
#define IP 0x0800
|
||||
#define ARP 0x0806
|
||||
#define RARP 0x8035
|
||||
|
||||
#define BOOTP_SERVER 67
|
||||
#define BOOTP_CLIENT 68
|
||||
#define TFTP_PORT 69
|
||||
#define SUNRPC_PORT 111
|
||||
|
||||
#define IP_UDP 17
|
||||
/* Same after going through htonl */
|
||||
#define IP_BROADCAST 0xFFFFFFFF
|
||||
|
||||
#define ARP_REQUEST 1
|
||||
#define ARP_REPLY 2
|
||||
|
||||
#define BOOTP_REQUEST 1
|
||||
#define BOOTP_REPLY 2
|
||||
|
||||
#define TAG_LEN(p) (*((p)+1))
|
||||
#define RFC1533_COOKIE 99, 130, 83, 99
|
||||
#define RFC1533_PAD 0
|
||||
#define RFC1533_NETMASK 1
|
||||
#define RFC1533_TIMEOFFSET 2
|
||||
#define RFC1533_GATEWAY 3
|
||||
#define RFC1533_TIMESERVER 4
|
||||
#define RFC1533_IEN116NS 5
|
||||
#define RFC1533_DNS 6
|
||||
#define RFC1533_LOGSERVER 7
|
||||
#define RFC1533_COOKIESERVER 8
|
||||
#define RFC1533_LPRSERVER 9
|
||||
#define RFC1533_IMPRESSSERVER 10
|
||||
#define RFC1533_RESOURCESERVER 11
|
||||
#define RFC1533_HOSTNAME 12
|
||||
#define RFC1533_BOOTFILESIZE 13
|
||||
#define RFC1533_MERITDUMPFILE 14
|
||||
#define RFC1533_DOMAINNAME 15
|
||||
#define RFC1533_SWAPSERVER 16
|
||||
#define RFC1533_ROOTPATH 17
|
||||
#define RFC1533_EXTENSIONPATH 18
|
||||
#define RFC1533_IPFORWARDING 19
|
||||
#define RFC1533_IPSOURCEROUTING 20
|
||||
#define RFC1533_IPPOLICYFILTER 21
|
||||
#define RFC1533_IPMAXREASSEMBLY 22
|
||||
#define RFC1533_IPTTL 23
|
||||
#define RFC1533_IPMTU 24
|
||||
#define RFC1533_IPMTUPLATEAU 25
|
||||
#define RFC1533_INTMTU 26
|
||||
#define RFC1533_INTLOCALSUBNETS 27
|
||||
#define RFC1533_INTBROADCAST 28
|
||||
#define RFC1533_INTICMPDISCOVER 29
|
||||
#define RFC1533_INTICMPRESPOND 30
|
||||
#define RFC1533_INTROUTEDISCOVER 31
|
||||
#define RFC1533_INTROUTESOLICIT 32
|
||||
#define RFC1533_INTSTATICROUTES 33
|
||||
#define RFC1533_LLTRAILERENCAP 34
|
||||
#define RFC1533_LLARPCACHETMO 35
|
||||
#define RFC1533_LLETHERNETENCAP 36
|
||||
#define RFC1533_TCPTTL 37
|
||||
#define RFC1533_TCPKEEPALIVETMO 38
|
||||
#define RFC1533_TCPKEEPALIVEGB 39
|
||||
#define RFC1533_NISDOMAIN 40
|
||||
#define RFC1533_NISSERVER 41
|
||||
#define RFC1533_NTPSERVER 42
|
||||
#define RFC1533_VENDOR 43
|
||||
#define RFC1533_NBNS 44
|
||||
#define RFC1533_NBDD 45
|
||||
#define RFC1533_NBNT 46
|
||||
#define RFC1533_NBSCOPE 47
|
||||
#define RFC1533_XFS 48
|
||||
#define RFC1533_XDM 49
|
||||
#ifndef NO_DHCP_SUPPORT
|
||||
#define RFC2132_REQ_ADDR 50
|
||||
#define RFC2132_MSG_TYPE 53
|
||||
#define RFC2132_SRV_ID 54
|
||||
#define RFC2132_PARAM_LIST 55
|
||||
#define RFC2132_MAX_SIZE 57
|
||||
#define RFC2132_VENDOR_CLASS_ID 60
|
||||
|
||||
#define DHCPDISCOVER 1
|
||||
#define DHCPOFFER 2
|
||||
#define DHCPREQUEST 3
|
||||
#define DHCPACK 5
|
||||
#endif /* NO_DHCP_SUPPORT */
|
||||
|
||||
#define RFC1533_VENDOR_MAJOR 0
|
||||
#define RFC1533_VENDOR_MINOR 0
|
||||
|
||||
#define RFC1533_VENDOR_MAGIC 128
|
||||
#define RFC1533_VENDOR_ADDPARM 129
|
||||
#define RFC1533_VENDOR_ETHDEV 130
|
||||
#ifdef IMAGE_FREEBSD
|
||||
#define RFC1533_VENDOR_HOWTO 132
|
||||
#endif
|
||||
#define RFC1533_VENDOR_MNUOPTS 160
|
||||
#define RFC1533_VENDOR_SELECTION 176
|
||||
#define RFC1533_VENDOR_MOTD 184
|
||||
#define RFC1533_VENDOR_NUMOFMOTD 8
|
||||
#define RFC1533_VENDOR_IMG 192
|
||||
#define RFC1533_VENDOR_NUMOFIMG 16
|
||||
|
||||
#define RFC1533_END 255
|
||||
|
||||
#define BOOTP_VENDOR_LEN 64
|
||||
#ifndef NO_DHCP_SUPPORT
|
||||
#define DHCP_OPT_LEN 312
|
||||
#endif /* NO_DHCP_SUPPORT */
|
||||
|
||||
#define TFTP_DEFAULTSIZE_PACKET 512
|
||||
#define TFTP_MAX_PACKET 1432 /* 512 */
|
||||
|
||||
#define TFTP_RRQ 1
|
||||
#define TFTP_WRQ 2
|
||||
#define TFTP_DATA 3
|
||||
#define TFTP_ACK 4
|
||||
#define TFTP_ERROR 5
|
||||
#define TFTP_OACK 6
|
||||
|
||||
#define TFTP_CODE_EOF 1
|
||||
#define TFTP_CODE_MORE 2
|
||||
#define TFTP_CODE_ERROR 3
|
||||
#define TFTP_CODE_BOOT 4
|
||||
#define TFTP_CODE_CFG 5
|
||||
|
||||
#define AWAIT_ARP 0
|
||||
#define AWAIT_BOOTP 1
|
||||
#define AWAIT_TFTP 2
|
||||
#define AWAIT_RARP 3
|
||||
#define AWAIT_RPC 4
|
||||
#define AWAIT_QDRAIN 5 /* drain queue, process ARP requests */
|
||||
|
||||
typedef struct {
|
||||
unsigned long s_addr;
|
||||
} in_addr;
|
||||
|
||||
struct arptable_t {
|
||||
in_addr ipaddr;
|
||||
unsigned char node[6];
|
||||
};
|
||||
|
||||
/*
|
||||
* A pity sipaddr and tipaddr are not longword aligned or we could use
|
||||
* in_addr. No, I don't want to use #pragma packed.
|
||||
*/
|
||||
struct arprequest {
|
||||
unsigned short hwtype;
|
||||
unsigned short protocol;
|
||||
char hwlen;
|
||||
char protolen;
|
||||
unsigned short opcode;
|
||||
char shwaddr[6];
|
||||
char sipaddr[4];
|
||||
char thwaddr[6];
|
||||
char tipaddr[4];
|
||||
};
|
||||
|
||||
struct iphdr {
|
||||
char verhdrlen;
|
||||
char service;
|
||||
unsigned short len;
|
||||
unsigned short ident;
|
||||
unsigned short frags;
|
||||
char ttl;
|
||||
char protocol;
|
||||
unsigned short chksum;
|
||||
in_addr src;
|
||||
in_addr dest;
|
||||
};
|
||||
|
||||
struct udphdr {
|
||||
unsigned short src;
|
||||
unsigned short dest;
|
||||
unsigned short len;
|
||||
unsigned short chksum;
|
||||
};
|
||||
|
||||
/* Format of a bootp packet */
|
||||
struct bootp_t {
|
||||
char bp_op;
|
||||
char bp_htype;
|
||||
char bp_hlen;
|
||||
char bp_hops;
|
||||
unsigned long bp_xid;
|
||||
unsigned short bp_secs;
|
||||
unsigned short unused;
|
||||
in_addr bp_ciaddr;
|
||||
in_addr bp_yiaddr;
|
||||
in_addr bp_siaddr;
|
||||
in_addr bp_giaddr;
|
||||
char bp_hwaddr[16];
|
||||
char bp_sname[64];
|
||||
char bp_file[128];
|
||||
#ifdef NO_DHCP_SUPPORT
|
||||
char bp_vend[BOOTP_VENDOR_LEN];
|
||||
#else
|
||||
char bp_vend[DHCP_OPT_LEN];
|
||||
#endif /* NO_DHCP_SUPPORT */
|
||||
};
|
||||
|
||||
/* Format of a bootp IP packet */
|
||||
struct bootpip_t
|
||||
{
|
||||
struct iphdr ip;
|
||||
struct udphdr udp;
|
||||
struct bootp_t bp;
|
||||
};
|
||||
|
||||
/* Format of bootp packet with extensions */
|
||||
struct bootpd_t {
|
||||
struct bootp_t bootp_reply;
|
||||
unsigned char bootp_extension[MAX_BOOTP_EXTLEN];
|
||||
};
|
||||
|
||||
#define KERNEL_BUF (BOOTP_DATA_ADDR->bootp_reply.bp_file)
|
||||
|
||||
struct tftp_t {
|
||||
struct iphdr ip;
|
||||
struct udphdr udp;
|
||||
unsigned short opcode;
|
||||
union {
|
||||
char rrq[TFTP_DEFAULTSIZE_PACKET];
|
||||
struct {
|
||||
unsigned short block;
|
||||
char download[TFTP_MAX_PACKET];
|
||||
} data;
|
||||
struct {
|
||||
unsigned short block;
|
||||
} ack;
|
||||
struct {
|
||||
unsigned short errcode;
|
||||
char errmsg[TFTP_DEFAULTSIZE_PACKET];
|
||||
} err;
|
||||
struct {
|
||||
char data[TFTP_DEFAULTSIZE_PACKET+2];
|
||||
} oack;
|
||||
} u;
|
||||
};
|
||||
|
||||
/* define a smaller tftp packet solely for making requests to conserve stack
|
||||
512 bytes should be enough */
|
||||
struct tftpreq_t {
|
||||
struct iphdr ip;
|
||||
struct udphdr udp;
|
||||
unsigned short opcode;
|
||||
union {
|
||||
char rrq[512];
|
||||
struct {
|
||||
unsigned short block;
|
||||
} ack;
|
||||
struct {
|
||||
unsigned short errcode;
|
||||
char errmsg[512-2];
|
||||
} err;
|
||||
} u;
|
||||
};
|
||||
|
||||
#define TFTP_MIN_PACKET (sizeof(struct iphdr) + sizeof(struct udphdr) + 4)
|
||||
|
||||
struct rpc_t {
|
||||
struct iphdr ip;
|
||||
struct udphdr udp;
|
||||
union {
|
||||
char data[300]; /* longest RPC call must fit!!!! */
|
||||
struct {
|
||||
long id;
|
||||
long type;
|
||||
long rpcvers;
|
||||
long prog;
|
||||
long vers;
|
||||
long proc;
|
||||
long data[1];
|
||||
} call;
|
||||
struct {
|
||||
long id;
|
||||
long type;
|
||||
long rstatus;
|
||||
long verifier;
|
||||
long v2;
|
||||
long astatus;
|
||||
long data[1];
|
||||
} reply;
|
||||
} u;
|
||||
};
|
||||
|
||||
#define PROG_PORTMAP 100000
|
||||
#define PROG_NFS 100003
|
||||
#define PROG_MOUNT 100005
|
||||
|
||||
#define MSG_CALL 0
|
||||
#define MSG_REPLY 1
|
||||
|
||||
#define PORTMAP_GETPORT 3
|
||||
|
||||
#define MOUNT_ADDENTRY 1
|
||||
#define MOUNT_UMOUNTALL 4
|
||||
|
||||
#define NFS_LOOKUP 4
|
||||
#define NFS_READ 6
|
||||
|
||||
#define NFS_FHSIZE 32
|
||||
|
||||
#define NFSERR_PERM 1
|
||||
#define NFSERR_NOENT 2
|
||||
#define NFSERR_ACCES 13
|
||||
|
||||
/* Block size used for NFS read accesses. A RPC reply packet (including all
|
||||
* headers) must fit within a single Ethernet frame to avoid fragmentation.
|
||||
* Chosen to be a power of two, as most NFS servers are optimized for this. */
|
||||
#define NFS_READ_SIZE 1024
|
||||
|
||||
#define FLOPPY_BOOT_LOCATION 0x7c00
|
||||
|
||||
#define ROM_INFO_LOCATION 0x7dfa
|
||||
/* at end of floppy boot block */
|
||||
|
||||
struct rom_info {
|
||||
unsigned short rom_segment;
|
||||
unsigned short rom_length;
|
||||
};
|
||||
|
||||
extern inline int rom_address_ok(struct rom_info *rom, int assigned_rom_segment)
|
||||
{
|
||||
return (assigned_rom_segment < 0xC000
|
||||
|| assigned_rom_segment == rom->rom_segment);
|
||||
}
|
||||
|
||||
/* Define a type for use by setjmp and longjmp */
|
||||
typedef struct {
|
||||
unsigned long buf[7];
|
||||
} jmpbuf[1];
|
||||
|
||||
/* Define a type for passing info to a loaded program */
|
||||
struct ebinfo {
|
||||
unsigned char major, minor; /* Version */
|
||||
unsigned short flags; /* Bit flags */
|
||||
};
|
||||
|
||||
/***************************************************************************
|
||||
External prototypes
|
||||
***************************************************************************/
|
||||
/* main.c */
|
||||
extern int tftp P((const char *name, int (*)(unsigned char *, int, int, int)));
|
||||
extern int udp_transmit P((unsigned long destip, unsigned int srcsock,
|
||||
unsigned int destsock, int len, const void *buf));
|
||||
extern int await_reply P((int type, int ival, void *ptr, int timeout));
|
||||
extern int decode_rfc1533 P((unsigned char *, int, int, int));
|
||||
extern void rfc951_sleep P((int));
|
||||
extern void cleanup P((void));
|
||||
|
||||
/* nfs.c */
|
||||
extern void rpc_init(void);
|
||||
extern int nfs P((const char *name, int (*)(unsigned char *, int, int, int)));
|
||||
extern void nfs_umountall P((int));
|
||||
|
||||
/* config.c */
|
||||
extern void print_config(void);
|
||||
extern void eth_reset(void);
|
||||
extern int eth_probe(void);
|
||||
extern int eth_poll(void);
|
||||
extern void eth_transmit(const char *d, unsigned int t, unsigned int s, const void *p);
|
||||
extern void eth_disable(void);
|
||||
|
||||
/* bootmenu.c */
|
||||
extern void bootmenu P((int));
|
||||
extern void show_motd P((void));
|
||||
extern void parse_menuopts P((char *,int));
|
||||
extern void selectImage P((char **));
|
||||
|
||||
/* osloader.c */
|
||||
#if defined(AOUT_IMAGE) || defined(ELF_IMAGE)
|
||||
extern int howto;
|
||||
#endif
|
||||
extern int os_download P((unsigned int, unsigned char *,unsigned int));
|
||||
|
||||
/* misc.c */
|
||||
extern void twiddle P((void));
|
||||
extern void sleep P((int secs));
|
||||
extern int strcasecmp P((char *a, char *b));
|
||||
extern char *substr P((char *a, char *b));
|
||||
extern int getdec P((char **));
|
||||
extern void printf P((const char *, ...));
|
||||
extern int sprintf P((char *, const char *, ...));
|
||||
extern int inet_aton P((char *p, in_addr *i));
|
||||
extern void gateA20_set P((void));
|
||||
extern void gateA20_unset P((void));
|
||||
extern void putchar P((int));
|
||||
extern int getchar P((void));
|
||||
extern int iskey P((void));
|
||||
|
||||
/* start*.S */
|
||||
extern int console_getc P((void));
|
||||
extern void console_putc P((int));
|
||||
extern int console_ischar P((void));
|
||||
extern int getshift P((void));
|
||||
extern unsigned int memsize P((void));
|
||||
extern unsigned short basememsize P((void));
|
||||
extern void disk_init P((void));
|
||||
extern unsigned int disk_read P((int drv,int c,int h,int s,char *buf));
|
||||
extern void xstart P((unsigned long, unsigned long, char *));
|
||||
#ifdef IMAGE_MULTIBOOT
|
||||
extern void xend P((void));
|
||||
#endif
|
||||
extern unsigned long currticks P((void));
|
||||
extern int setjmp P((jmpbuf env));
|
||||
extern void longjmp P((jmpbuf env, int val));
|
||||
extern void exit P((int status));
|
||||
|
||||
/* serial.S */
|
||||
extern int serial_getc P((void));
|
||||
extern void serial_putc P((int));
|
||||
extern int serial_ischar P((void));
|
||||
extern int serial_init P((void));
|
||||
|
||||
/* ansiesc.c */
|
||||
extern void ansi_reset P((void));
|
||||
extern void enable_cursor P((int));
|
||||
extern void ansi_putc P((unsigned int));
|
||||
|
||||
/* md5.c */
|
||||
extern void md5_put P((unsigned int ch));
|
||||
extern void md5_done P((unsigned char *buf));
|
||||
|
||||
/* floppy.c */
|
||||
extern int bootdisk P((int dev,int part));
|
||||
|
||||
/***************************************************************************
|
||||
External variables
|
||||
***************************************************************************/
|
||||
/* main.c */
|
||||
extern struct rom_info rom;
|
||||
extern char *hostname;
|
||||
extern int hostnamelen;
|
||||
extern jmpbuf jmp_bootmenu;
|
||||
extern struct arptable_t arptable[MAX_ARP];
|
||||
#ifdef IMAGE_MENU
|
||||
extern int menutmo,menudefault;
|
||||
extern unsigned char *defparams;
|
||||
extern int defparams_max;
|
||||
#endif
|
||||
#ifdef MOTD
|
||||
extern char *motd[RFC1533_VENDOR_NUMOFMOTD];
|
||||
#endif
|
||||
#ifdef BOOTP_DATA_AT_0x93C00
|
||||
#define BOOTP_DATA_ADDR ((struct bootpd_t *)0x93C00)
|
||||
#else
|
||||
extern struct bootpd_t bootp_data;
|
||||
#define BOOTP_DATA_ADDR (&bootp_data)
|
||||
#endif
|
||||
extern unsigned char *end_of_rfc1533;
|
||||
#ifdef IMAGE_FREEBSD
|
||||
extern int freebsd_howto;
|
||||
#endif
|
||||
|
||||
/* config.c */
|
||||
extern struct nic nic;
|
||||
|
||||
/* bootmenu.c */
|
||||
|
||||
/* osloader.c */
|
||||
|
||||
/* created by linker */
|
||||
extern char _start[], edata[], end[];
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
187
src/etherboot/linux-asm-io.h
Normal file
187
src/etherboot/linux-asm-io.h
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
#ifndef _ASM_IO_H
|
||||
#define _ASM_IO_H
|
||||
|
||||
/*
|
||||
* This file contains the definitions for the x86 IO instructions
|
||||
* inb/inw/inl/outb/outw/outl and the "string versions" of the same
|
||||
* (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing"
|
||||
* versions of the single-IO instructions (inb_p/inw_p/..).
|
||||
*
|
||||
* This file is not meant to be obfuscating: it's just complicated
|
||||
* to (a) handle it all in a way that makes gcc able to optimize it
|
||||
* as well as possible and (b) trying to avoid writing the same thing
|
||||
* over and over again with slight variations and possibly making a
|
||||
* mistake somewhere.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Thanks to James van Artsdalen for a better timing-fix than
|
||||
* the two short jumps: using outb's to a nonexistent port seems
|
||||
* to guarantee better timings even on fast machines.
|
||||
*
|
||||
* On the other hand, I'd like to be sure of a non-existent port:
|
||||
* I feel a bit unsafe about using 0x80 (should be safe, though)
|
||||
*
|
||||
* Linus
|
||||
*/
|
||||
|
||||
#ifdef SLOW_IO_BY_JUMPING
|
||||
#define __SLOW_DOWN_IO __asm__ __volatile__("jmp 1f\n1:\tjmp 1f\n1:")
|
||||
#else
|
||||
#define __SLOW_DOWN_IO __asm__ __volatile__("outb %al,$0x80")
|
||||
#endif
|
||||
|
||||
#ifdef REALLY_SLOW_IO
|
||||
#define SLOW_DOWN_IO { __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; }
|
||||
#else
|
||||
#define SLOW_DOWN_IO __SLOW_DOWN_IO
|
||||
#endif
|
||||
|
||||
/*
|
||||
* readX/writeX() are used to access memory mapped devices. On some
|
||||
* architectures the memory mapped IO stuff needs to be accessed
|
||||
* differently. On the x86 architecture, we just read/write the
|
||||
* memory location directly.
|
||||
*/
|
||||
#define readb(addr) (*(volatile unsigned char *) (addr))
|
||||
#define readw(addr) (*(volatile unsigned short *) (addr))
|
||||
#define readl(addr) (*(volatile unsigned int *) (addr))
|
||||
|
||||
#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
|
||||
#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
|
||||
#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
|
||||
|
||||
#define memset_io(a,b,c) memset((void *)(a),(b),(c))
|
||||
#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c))
|
||||
#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c))
|
||||
|
||||
/*
|
||||
* Again, i386 does not require mem IO specific function.
|
||||
*/
|
||||
|
||||
#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void *)(b),(c),(d))
|
||||
|
||||
/*
|
||||
* Talk about misusing macros..
|
||||
*/
|
||||
|
||||
#define __OUT1(s,x) \
|
||||
extern void __out##s(unsigned x value, unsigned short port); \
|
||||
extern inline void __out##s(unsigned x value, unsigned short port) {
|
||||
|
||||
#define __OUT2(s,s1,s2) \
|
||||
__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
|
||||
|
||||
#define __OUT(s,s1,x) \
|
||||
__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); } \
|
||||
__OUT1(s##c,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); } \
|
||||
__OUT1(s##_p,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); SLOW_DOWN_IO; } \
|
||||
__OUT1(s##c_p,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); SLOW_DOWN_IO; }
|
||||
|
||||
#define __IN1(s,x) \
|
||||
extern unsigned x __in##s(unsigned short port); \
|
||||
extern inline unsigned x __in##s(unsigned short port) { unsigned x _v;
|
||||
|
||||
#define __IN2(s,s1,s2) \
|
||||
__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
|
||||
|
||||
#define __IN(s,s1,x,i...) \
|
||||
__IN1(s,x) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); return _v; } \
|
||||
__IN1(s##c,x) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); return _v; } \
|
||||
__IN1(s##_p,x) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); SLOW_DOWN_IO; return _v; } \
|
||||
__IN1(s##c_p,x) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); SLOW_DOWN_IO; return _v; }
|
||||
|
||||
#define __INS(s) \
|
||||
extern void ins##s(unsigned short port, void * addr, unsigned long count); \
|
||||
extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \
|
||||
{ __asm__ __volatile__ ("cld ; rep ; ins" #s \
|
||||
: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
|
||||
|
||||
#define __OUTS(s) \
|
||||
extern void outs##s(unsigned short port, const void * addr, unsigned long count); \
|
||||
extern inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
|
||||
{ __asm__ __volatile__ ("cld ; rep ; outs" #s \
|
||||
: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
|
||||
|
||||
__IN(b,"", char)
|
||||
__IN(w,"",short)
|
||||
__IN(l,"", long)
|
||||
|
||||
__OUT(b,"b",char)
|
||||
__OUT(w,"w",short)
|
||||
__OUT(l,,int)
|
||||
|
||||
__INS(b)
|
||||
__INS(w)
|
||||
__INS(l)
|
||||
|
||||
__OUTS(b)
|
||||
__OUTS(w)
|
||||
__OUTS(l)
|
||||
|
||||
/*
|
||||
* Note that due to the way __builtin_constant_p() works, you
|
||||
* - can't use it inside a inline function (it will never be true)
|
||||
* - you don't have to worry about side effects within the __builtin..
|
||||
*/
|
||||
#define outb(val,port) \
|
||||
((__builtin_constant_p((port)) && (port) < 256) ? \
|
||||
__outbc((val),(port)) : \
|
||||
__outb((val),(port)))
|
||||
|
||||
#define inb(port) \
|
||||
((__builtin_constant_p((port)) && (port) < 256) ? \
|
||||
__inbc(port) : \
|
||||
__inb(port))
|
||||
|
||||
#define outb_p(val,port) \
|
||||
((__builtin_constant_p((port)) && (port) < 256) ? \
|
||||
__outbc_p((val),(port)) : \
|
||||
__outb_p((val),(port)))
|
||||
|
||||
#define inb_p(port) \
|
||||
((__builtin_constant_p((port)) && (port) < 256) ? \
|
||||
__inbc_p(port) : \
|
||||
__inb_p(port))
|
||||
|
||||
#define outw(val,port) \
|
||||
((__builtin_constant_p((port)) && (port) < 256) ? \
|
||||
__outwc((val),(port)) : \
|
||||
__outw((val),(port)))
|
||||
|
||||
#define inw(port) \
|
||||
((__builtin_constant_p((port)) && (port) < 256) ? \
|
||||
__inwc(port) : \
|
||||
__inw(port))
|
||||
|
||||
#define outw_p(val,port) \
|
||||
((__builtin_constant_p((port)) && (port) < 256) ? \
|
||||
__outwc_p((val),(port)) : \
|
||||
__outw_p((val),(port)))
|
||||
|
||||
#define inw_p(port) \
|
||||
((__builtin_constant_p((port)) && (port) < 256) ? \
|
||||
__inwc_p(port) : \
|
||||
__inw_p(port))
|
||||
|
||||
#define outl(val,port) \
|
||||
((__builtin_constant_p((port)) && (port) < 256) ? \
|
||||
__outlc((val),(port)) : \
|
||||
__outl((val),(port)))
|
||||
|
||||
#define inl(port) \
|
||||
((__builtin_constant_p((port)) && (port) < 256) ? \
|
||||
__inlc(port) : \
|
||||
__inl(port))
|
||||
|
||||
#define outl_p(val,port) \
|
||||
((__builtin_constant_p((port)) && (port) < 256) ? \
|
||||
__outlc_p((val),(port)) : \
|
||||
__outl_p((val),(port)))
|
||||
|
||||
#define inl_p(port) \
|
||||
((__builtin_constant_p((port)) && (port) < 256) ? \
|
||||
__inlc_p(port) : \
|
||||
__inl_p(port))
|
||||
|
||||
#endif
|
||||
253
src/etherboot/linux-asm-string.h
Normal file
253
src/etherboot/linux-asm-string.h
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
* Taken from Linux /usr/include/asm/string.h
|
||||
* All except memcpy, memmove, memset and memcmp removed.
|
||||
*/
|
||||
|
||||
#ifndef _I386_STRING_H_
|
||||
#define _I386_STRING_H_
|
||||
|
||||
#include <types.h>
|
||||
/*
|
||||
* This string-include defines all string functions as inline
|
||||
* functions. Use gcc. It also assumes ds=es=data space, this should be
|
||||
* normal. Most of the string-functions are rather heavily hand-optimized,
|
||||
* see especially strtok,strstr,str[c]spn. They should work, but are not
|
||||
* very easy to understand. Everything is done entirely within the register
|
||||
* set, making the functions fast and clean. String instructions have been
|
||||
* used through-out, making for "slightly" unclear code :-)
|
||||
*
|
||||
* NO Copyright (C) 1991, 1992 Linus Torvalds,
|
||||
* consider these trivial functions to be PD.
|
||||
*/
|
||||
|
||||
extern void *__memcpy(void * to, const void * from, size_t n);
|
||||
extern void *__constant_memcpy(void * to, const void * from, size_t n);
|
||||
extern void *memmove(void * dest,const void * src, size_t n);
|
||||
extern void *__memset_generic(void * s, char c,size_t count);
|
||||
extern void *__constant_c_memset(void * s, unsigned long c, size_t count);
|
||||
extern void *__constant_c_and_count_memset(void * s, unsigned long pattern, size_t count);
|
||||
|
||||
|
||||
extern inline void * __memcpy(void * to, const void * from, size_t n)
|
||||
{
|
||||
int d0, d1, d2;
|
||||
__asm__ __volatile__(
|
||||
"cld\n\t"
|
||||
"rep ; movsl\n\t"
|
||||
"testb $2,%b4\n\t"
|
||||
"je 1f\n\t"
|
||||
"movsw\n"
|
||||
"1:\ttestb $1,%b4\n\t"
|
||||
"je 2f\n\t"
|
||||
"movsb\n"
|
||||
"2:"
|
||||
: "=&c" (d0), "=&D" (d1), "=&S" (d2)
|
||||
:"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
|
||||
: "memory");
|
||||
return (to);
|
||||
}
|
||||
|
||||
/*
|
||||
* This looks horribly ugly, but the compiler can optimize it totally,
|
||||
* as the count is constant.
|
||||
*/
|
||||
extern inline void * __constant_memcpy(void * to, const void * from, size_t n)
|
||||
{
|
||||
switch (n) {
|
||||
case 0:
|
||||
return to;
|
||||
case 1:
|
||||
*(unsigned char *)to = *(const unsigned char *)from;
|
||||
return to;
|
||||
case 2:
|
||||
*(unsigned short *)to = *(const unsigned short *)from;
|
||||
return to;
|
||||
case 3:
|
||||
*(unsigned short *)to = *(const unsigned short *)from;
|
||||
*(2+(unsigned char *)to) = *(2+(const unsigned char *)from);
|
||||
return to;
|
||||
case 4:
|
||||
*(unsigned long *)to = *(const unsigned long *)from;
|
||||
return to;
|
||||
case 6: /* for Ethernet addresses */
|
||||
*(unsigned long *)to = *(const unsigned long *)from;
|
||||
*(2+(unsigned short *)to) = *(2+(const unsigned short *)from);
|
||||
return to;
|
||||
case 8:
|
||||
*(unsigned long *)to = *(const unsigned long *)from;
|
||||
*(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
|
||||
return to;
|
||||
case 12:
|
||||
*(unsigned long *)to = *(const unsigned long *)from;
|
||||
*(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
|
||||
*(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
|
||||
return to;
|
||||
case 16:
|
||||
*(unsigned long *)to = *(const unsigned long *)from;
|
||||
*(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
|
||||
*(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
|
||||
*(3+(unsigned long *)to) = *(3+(const unsigned long *)from);
|
||||
return to;
|
||||
case 20:
|
||||
*(unsigned long *)to = *(const unsigned long *)from;
|
||||
*(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
|
||||
*(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
|
||||
*(3+(unsigned long *)to) = *(3+(const unsigned long *)from);
|
||||
*(4+(unsigned long *)to) = *(4+(const unsigned long *)from);
|
||||
return to;
|
||||
}
|
||||
#define COMMON(x) \
|
||||
__asm__ __volatile__( \
|
||||
"cld\n\t" \
|
||||
"rep ; movsl" \
|
||||
x \
|
||||
: "=&c" (d0), "=&D" (d1), "=&S" (d2) \
|
||||
: "0" (n/4),"1" ((long) to),"2" ((long) from) \
|
||||
: "memory");
|
||||
{
|
||||
int d0, d1, d2;
|
||||
switch (n % 4) {
|
||||
case 0: COMMON(""); return to;
|
||||
case 1: COMMON("\n\tmovsb"); return to;
|
||||
case 2: COMMON("\n\tmovsw"); return to;
|
||||
default: COMMON("\n\tmovsw\n\tmovsb"); return to;
|
||||
}
|
||||
}
|
||||
|
||||
#undef COMMON
|
||||
}
|
||||
|
||||
#define __HAVE_ARCH_MEMCPY
|
||||
#define memcpy(t, f, n) \
|
||||
(__builtin_constant_p(n) ? \
|
||||
__constant_memcpy((t),(f),(n)) : \
|
||||
__memcpy((t),(f),(n)))
|
||||
|
||||
#define __HAVE_ARCH_MEMMOVE
|
||||
extern inline void * memmove(void * dest,const void * src, size_t n)
|
||||
{
|
||||
int d0, d1, d2;
|
||||
if (dest<src)
|
||||
__asm__ __volatile__(
|
||||
"cld\n\t"
|
||||
"rep\n\t"
|
||||
"movsb"
|
||||
: "=&c" (d0), "=&S" (d1), "=&D" (d2)
|
||||
:"0" (n),"1" (src),"2" (dest)
|
||||
: "memory");
|
||||
else
|
||||
__asm__ __volatile__(
|
||||
"std\n\t"
|
||||
"rep\n\t"
|
||||
"movsb\n\t"
|
||||
"cld"
|
||||
: "=&c" (d0), "=&S" (d1), "=&D" (d2)
|
||||
:"0" (n),
|
||||
"1" (n-1+(const char *)src),
|
||||
"2" (n-1+(char *)dest)
|
||||
:"memory");
|
||||
return dest;
|
||||
}
|
||||
|
||||
#define memcmp __builtin_memcmp
|
||||
|
||||
extern inline void * __memset_generic(void * s, char c,size_t count)
|
||||
{
|
||||
int d0, d1;
|
||||
__asm__ __volatile__(
|
||||
"cld\n\t"
|
||||
"rep\n\t"
|
||||
"stosb"
|
||||
: "=&c" (d0), "=&D" (d1)
|
||||
:"a" (c),"1" (s),"0" (count)
|
||||
:"memory");
|
||||
return s;
|
||||
}
|
||||
|
||||
/* we might want to write optimized versions of these later */
|
||||
#define __constant_count_memset(s,c,count) __memset_generic((s),(c),(count))
|
||||
|
||||
/*
|
||||
* memset(x,0,y) is a reasonably common thing to do, so we want to fill
|
||||
* things 32 bits at a time even when we don't know the size of the
|
||||
* area at compile-time..
|
||||
*/
|
||||
extern inline void * __constant_c_memset(void * s, unsigned long c, size_t count)
|
||||
{
|
||||
int d0, d1;
|
||||
__asm__ __volatile__(
|
||||
"cld\n\t"
|
||||
"rep ; stosl\n\t"
|
||||
"testb $2,%b3\n\t"
|
||||
"je 1f\n\t"
|
||||
"stosw\n"
|
||||
"1:\ttestb $1,%b3\n\t"
|
||||
"je 2f\n\t"
|
||||
"stosb\n"
|
||||
"2:"
|
||||
: "=&c" (d0), "=&D" (d1)
|
||||
:"a" (c), "q" (count), "0" (count/4), "1" ((long) s)
|
||||
:"memory");
|
||||
return (s);
|
||||
}
|
||||
|
||||
/*
|
||||
* This looks horribly ugly, but the compiler can optimize it totally,
|
||||
* as we by now know that both pattern and count is constant..
|
||||
*/
|
||||
extern inline void * __constant_c_and_count_memset(void * s, unsigned long pattern, size_t count)
|
||||
{
|
||||
switch (count) {
|
||||
case 0:
|
||||
return s;
|
||||
case 1:
|
||||
*(unsigned char *)s = pattern;
|
||||
return s;
|
||||
case 2:
|
||||
*(unsigned short *)s = pattern;
|
||||
return s;
|
||||
case 3:
|
||||
*(unsigned short *)s = pattern;
|
||||
*(2+(unsigned char *)s) = pattern;
|
||||
return s;
|
||||
case 4:
|
||||
*(unsigned long *)s = pattern;
|
||||
return s;
|
||||
}
|
||||
#define COMMON(x) \
|
||||
__asm__ __volatile__("cld\n\t" \
|
||||
"rep ; stosl" \
|
||||
x \
|
||||
: "=&c" (d0), "=&D" (d1) \
|
||||
: "a" (pattern),"0" (count/4),"1" ((long) s) \
|
||||
: "memory")
|
||||
{
|
||||
int d0, d1;
|
||||
switch (count % 4) {
|
||||
case 0: COMMON(""); return s;
|
||||
case 1: COMMON("\n\tstosb"); return s;
|
||||
case 2: COMMON("\n\tstosw"); return s;
|
||||
default: COMMON("\n\tstosw\n\tstosb"); return s;
|
||||
}
|
||||
}
|
||||
|
||||
#undef COMMON
|
||||
}
|
||||
|
||||
#define __constant_c_x_memset(s, c, count) \
|
||||
(__builtin_constant_p(count) ? \
|
||||
__constant_c_and_count_memset((s),(c),(count)) : \
|
||||
__constant_c_memset((s),(c),(count)))
|
||||
|
||||
#define __memset(s, c, count) \
|
||||
(__builtin_constant_p(count) ? \
|
||||
__constant_count_memset((s),(c),(count)) : \
|
||||
__memset_generic((s),(c),(count)))
|
||||
|
||||
#define __HAVE_ARCH_MEMSET
|
||||
#define memset(s, c, count) \
|
||||
(__builtin_constant_p(c) ? \
|
||||
__constant_c_x_memset((s),(c),(count)) : \
|
||||
__memset((s),(c),(count)))
|
||||
|
||||
#endif
|
||||
112
src/etherboot/netboot.c
Normal file
112
src/etherboot/netboot.c
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
#include <printk.h>
|
||||
#include <pciconf.h>
|
||||
#include <subr.h>
|
||||
#include <pci.h>
|
||||
#include <pci_ids.h>
|
||||
#include <cpu/p5/io.h>
|
||||
|
||||
|
||||
#include "nic.h"
|
||||
#include "sis900.h"
|
||||
#include "etherboot.h"
|
||||
|
||||
struct nic nic;
|
||||
unsigned char eth_addr[6];
|
||||
|
||||
int acpi_base;
|
||||
|
||||
void init_HR_TIMER(void)
|
||||
{
|
||||
int j;
|
||||
|
||||
outl(0x80000840, 0x0cf8);
|
||||
acpi_base = inb(0x0cfc) | 0x80;
|
||||
outb(acpi_base, 0x0cfc);
|
||||
|
||||
outl(0x80000874, 0x0cf8);
|
||||
acpi_base = inw(0x0cfc);
|
||||
|
||||
printk("init_HR_TIMER: acpi_base = %04x\n", acpi_base);
|
||||
|
||||
j = inw(acpi_base + 0x56) | 0x02; // HR_TMR control
|
||||
outw(j, acpi_base + 0x56); // activate HR_TMR
|
||||
}
|
||||
|
||||
inline unsigned long currticks(void)
|
||||
{
|
||||
unsigned long int j=0;
|
||||
|
||||
j = inl(acpi_base + 0x4c);
|
||||
j /= 55555; // HR_TMR runs at 1MHz, etherboot drivers expect 18.2Hz, but this will be close enough.
|
||||
|
||||
return(j);
|
||||
}
|
||||
|
||||
int test_display_tftp_callback(char *data, int block, int length, int eof)
|
||||
{
|
||||
int i;
|
||||
|
||||
#ifdef DEBUG
|
||||
printk("RECD block %u, length = %u:\n",block, length);
|
||||
#endif
|
||||
for(i=0; i<length; i++)
|
||||
if(!data[i])
|
||||
printk("|");
|
||||
else
|
||||
printk("%c",data[i]);
|
||||
#ifdef DEBUG
|
||||
if(eof)
|
||||
printk("\nEND OF FILE\n");
|
||||
|
||||
printk("====================\n");
|
||||
#endif
|
||||
return(-1);
|
||||
}
|
||||
|
||||
char buffer[1024];
|
||||
|
||||
void netboot_init()
|
||||
{
|
||||
struct pci_dev *pcidev;
|
||||
struct nic *result;
|
||||
unsigned short iobase = 0x0b001; // address = 0x0b00, I/O port space
|
||||
int rc=512;
|
||||
int i;
|
||||
|
||||
nic.node_addr = eth_addr;
|
||||
/* first, init the sis900 ethernet! */
|
||||
|
||||
pcidev = pci_find_device(PCI_VENDOR_ID_SI, 0x0900, (void *)NULL);
|
||||
pci_write_config_byte(pcidev, PCI_BASE_ADDRESS_0, iobase);
|
||||
|
||||
printk("\ncalling init_HR_TIMER\n");
|
||||
init_HR_TIMER();
|
||||
|
||||
result = sis900_probe(&nic, &iobase, pcidev);
|
||||
|
||||
printk("netboot_init : sis900_probe = %04x\n", (unsigned int) result);
|
||||
|
||||
memcpy(arptable[ARP_CLIENT].node, eth_addr, ETH_ALEN);
|
||||
|
||||
printk("doing rarp:\n");
|
||||
rarp();
|
||||
|
||||
printk("My IP address is: %04x\n",arptable[ARP_CLIENT].ipaddr.s_addr);
|
||||
printk("My server's IP address is: %04x\n",arptable[ARP_SERVER].ipaddr.s_addr);
|
||||
|
||||
#ifdef DEBUG
|
||||
printk("Now testing tftp, transferring cmdline\n");
|
||||
|
||||
// tftp("cmdline", test_display_tftp_callback);
|
||||
tftp_init("cmdline");
|
||||
while(rc == 512) {
|
||||
rc = tftp_fetchone(buffer);
|
||||
for(i=0; i<rc; i++)
|
||||
if(!buffer[i])
|
||||
printk("|");
|
||||
else
|
||||
printk("%c",buffer[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
31
src/etherboot/nic.h
Normal file
31
src/etherboot/nic.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2, or (at
|
||||
* your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef NIC_H
|
||||
#define NIC_H
|
||||
|
||||
/*
|
||||
* Structure returned from eth_probe and passed to other driver
|
||||
* functions.
|
||||
*/
|
||||
|
||||
struct nic
|
||||
{
|
||||
void (*reset)(struct nic *);
|
||||
int (*poll)(struct nic *);
|
||||
void (*transmit)(struct nic *, const char *d,
|
||||
unsigned int t, unsigned int s, const char *p);
|
||||
void (*disable)(struct nic *);
|
||||
int flags; /* driver specific flags */
|
||||
struct rom_info *rom_info; /* -> rom_info from main */
|
||||
unsigned char *node_addr;
|
||||
char *packet;
|
||||
unsigned int packetlen;
|
||||
void *priv_data; /* driver can hang private data here */
|
||||
};
|
||||
|
||||
#endif /* NIC_H */
|
||||
121
src/etherboot/osdep.h
Normal file
121
src/etherboot/osdep.h
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
#ifndef __OSDEP_H__
|
||||
#define __OSDEP_H__
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2, or (at
|
||||
* your option) any later version.
|
||||
*/
|
||||
|
||||
#define __LITTLE_ENDIAN /* x86 */
|
||||
|
||||
/* Taken from /usr/include/linux/hfs_sysdep.h */
|
||||
#if defined(__BIG_ENDIAN)
|
||||
# if !defined(__constant_htonl)
|
||||
# define __constant_htonl(x) (x)
|
||||
# endif
|
||||
# if !defined(__constant_htons)
|
||||
# define __constant_htons(x) (x)
|
||||
# endif
|
||||
#elif defined(__LITTLE_ENDIAN)
|
||||
# if !defined(__constant_htonl)
|
||||
# define __constant_htonl(x) \
|
||||
((unsigned long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \
|
||||
(((unsigned long int)(x) & 0x0000ff00U) << 8) | \
|
||||
(((unsigned long int)(x) & 0x00ff0000U) >> 8) | \
|
||||
(((unsigned long int)(x) & 0xff000000U) >> 24)))
|
||||
# endif
|
||||
# if !defined(__constant_htons)
|
||||
# define __constant_htons(x) \
|
||||
((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \
|
||||
(((unsigned short int)(x) & 0xff00) >> 8)))
|
||||
# endif
|
||||
#else
|
||||
# error "Don't know if bytes are big- or little-endian!"
|
||||
#endif
|
||||
|
||||
#define ntohl(x) \
|
||||
(__builtin_constant_p(x) ? \
|
||||
__constant_htonl((x)) : \
|
||||
__swap32(x))
|
||||
#define htonl(x) \
|
||||
(__builtin_constant_p(x) ? \
|
||||
__constant_htonl((x)) : \
|
||||
__swap32(x))
|
||||
#define ntohs(x) \
|
||||
(__builtin_constant_p(x) ? \
|
||||
__constant_htons((x)) : \
|
||||
__swap16(x))
|
||||
#define htons(x) \
|
||||
(__builtin_constant_p(x) ? \
|
||||
__constant_htons((x)) : \
|
||||
__swap16(x))
|
||||
|
||||
static inline unsigned long int __swap32(unsigned long int x)
|
||||
{
|
||||
__asm__("xchgb %b0,%h0\n\t"
|
||||
"rorl $16,%0\n\t"
|
||||
"xchgb %b0,%h0"
|
||||
: "=q" (x)
|
||||
: "0" (x));
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline unsigned short int __swap16(unsigned short int x)
|
||||
{
|
||||
__asm__("xchgb %b0,%h0"
|
||||
: "=q" (x)
|
||||
: "0" (x));
|
||||
return x;
|
||||
}
|
||||
|
||||
/* Make routines available to all */
|
||||
#define swap32(x) __swap32(x)
|
||||
#define swap16(x) __swap16(x)
|
||||
|
||||
/* Taken from asm/string-486.h */
|
||||
#define __HAVE_ARCH_STRNCMP
|
||||
extern inline int strncmp(const char * cs,const char * ct,int count)
|
||||
{
|
||||
register int __res;
|
||||
__asm__ __volatile__(
|
||||
"\n1:\tdecl %3\n\t"
|
||||
"js 2f\n\t"
|
||||
"movb (%1),%b0\n\t"
|
||||
"incl %1\n\t"
|
||||
"cmpb %b0,(%2)\n\t"
|
||||
"jne 3f\n\t"
|
||||
"incl %2\n\t"
|
||||
"testb %b0,%b0\n\t"
|
||||
"jne 1b\n"
|
||||
"2:\txorl %0,%0\n\t"
|
||||
"jmp 4f\n"
|
||||
"3:\tmovl $1,%0\n\t"
|
||||
"jb 4f\n\t"
|
||||
"negl %0\n"
|
||||
"4:"
|
||||
:"=q" (__res), "=r" (cs), "=r" (ct), "=r" (count)
|
||||
:"1" (cs), "2" (ct), "3" (count));
|
||||
return __res;
|
||||
}
|
||||
|
||||
#include "linux-asm-string.h"
|
||||
#include "linux-asm-io.h"
|
||||
|
||||
typedef unsigned long Address;
|
||||
|
||||
/* ANSI prototyping macro */
|
||||
#ifdef __STDC__
|
||||
#define P(x) x
|
||||
#else
|
||||
#define P(x) ()
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
178
src/etherboot/pci.h
Normal file
178
src/etherboot/pci.h
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
#ifndef PCI_H
|
||||
#define PCI_H
|
||||
|
||||
/*
|
||||
** Support for NE2000 PCI clones added David Monro June 1997
|
||||
** Generalised for other PCI NICs by Ken Yap July 1997
|
||||
**
|
||||
** Most of this is taken from:
|
||||
**
|
||||
** /usr/src/linux/drivers/pci/pci.c
|
||||
** /usr/src/linux/include/linux/pci.h
|
||||
** /usr/src/linux/arch/i386/bios32.c
|
||||
** /usr/src/linux/include/linux/bios32.h
|
||||
** /usr/src/linux/drivers/net/ne.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2, or (at
|
||||
* your option) any later version.
|
||||
*/
|
||||
|
||||
#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */
|
||||
#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */
|
||||
#define PCI_LATENCY_TIMER 0x0d /* 8 bits */
|
||||
|
||||
#define PCIBIOS_PCI_FUNCTION_ID 0xb1XX
|
||||
#define PCIBIOS_PCI_BIOS_PRESENT 0xb101
|
||||
#define PCIBIOS_FIND_PCI_DEVICE 0xb102
|
||||
#define PCIBIOS_FIND_PCI_CLASS_CODE 0xb103
|
||||
#define PCIBIOS_GENERATE_SPECIAL_CYCLE 0xb106
|
||||
#define PCIBIOS_READ_CONFIG_BYTE 0xb108
|
||||
#define PCIBIOS_READ_CONFIG_WORD 0xb109
|
||||
#define PCIBIOS_READ_CONFIG_DWORD 0xb10a
|
||||
#define PCIBIOS_WRITE_CONFIG_BYTE 0xb10b
|
||||
#define PCIBIOS_WRITE_CONFIG_WORD 0xb10c
|
||||
#define PCIBIOS_WRITE_CONFIG_DWORD 0xb10d
|
||||
|
||||
#define PCI_VENDOR_ID 0x00 /* 16 bits */
|
||||
#define PCI_DEVICE_ID 0x02 /* 16 bits */
|
||||
#define PCI_COMMAND 0x04 /* 16 bits */
|
||||
|
||||
#define PCI_REVISION 0x08 /* 8 bits */
|
||||
#define PCI_CLASS_CODE 0x0b /* 8 bits */
|
||||
#define PCI_SUBCLASS_CODE 0x0a /* 8 bits */
|
||||
#define PCI_HEADER_TYPE 0x0e /* 8 bits */
|
||||
|
||||
#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */
|
||||
#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits */
|
||||
#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits */
|
||||
#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */
|
||||
#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */
|
||||
#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */
|
||||
|
||||
#ifndef PCI_BASE_ADDRESS_IO_MASK
|
||||
#define PCI_BASE_ADDRESS_IO_MASK (~0x03)
|
||||
#endif
|
||||
#define PCI_BASE_ADDRESS_SPACE_IO 0x01
|
||||
#define PCI_ROM_ADDRESS 0x30 /* 32 bits */
|
||||
#define PCI_ROM_ADDRESS_ENABLE 0x01 /* Write 1 to enable ROM,
|
||||
bits 31..11 are address,
|
||||
10..2 are reserved */
|
||||
|
||||
#define PCI_FUNC(devfn) ((devfn) & 0x07)
|
||||
|
||||
#define BIOS32_SIGNATURE (('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24))
|
||||
|
||||
/* PCI signature: "PCI " */
|
||||
#define PCI_SIGNATURE (('P' << 0) + ('C' << 8) + ('I' << 16) + (' ' << 24))
|
||||
|
||||
/* PCI service signature: "$PCI" */
|
||||
#define PCI_SERVICE (('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24))
|
||||
|
||||
union bios32 {
|
||||
struct {
|
||||
unsigned long signature; /* _32_ */
|
||||
unsigned long entry; /* 32 bit physical address */
|
||||
unsigned char revision; /* Revision level, 0 */
|
||||
unsigned char length; /* Length in paragraphs should be 01 */
|
||||
unsigned char checksum; /* All bytes must add up to zero */
|
||||
unsigned char reserved[5]; /* Must be zero */
|
||||
} fields;
|
||||
char chars[16];
|
||||
};
|
||||
|
||||
#define KERN_CODE_SEG 0x8 /* This _MUST_ match start.S */
|
||||
|
||||
/* Stuff for asm */
|
||||
#define save_flags(x) \
|
||||
__asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */ :"memory")
|
||||
|
||||
#define cli() __asm__ __volatile__ ("cli": : :"memory")
|
||||
|
||||
#define restore_flags(x) \
|
||||
__asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory")
|
||||
|
||||
#define PCI_VENDOR_ID_ADMTEK 0x1317
|
||||
#define PCI_DEVICE_ID_ADMTEK_0985 0x0985
|
||||
#define PCI_VENDOR_ID_REALTEK 0x10ec
|
||||
#define PCI_DEVICE_ID_REALTEK_8029 0x8029
|
||||
#define PCI_DEVICE_ID_REALTEK_8139 0x8139
|
||||
#define PCI_VENDOR_ID_WINBOND2 0x1050
|
||||
#define PCI_DEVICE_ID_WINBOND2_89C940 0x0940
|
||||
#define PCI_DEVICE_ID_WINBOND2_89C840 0x0840
|
||||
#define PCI_VENDOR_ID_COMPEX 0x11f6
|
||||
#define PCI_DEVICE_ID_COMPEX_RL2000 0x1401
|
||||
#define PCI_DEVICE_ID_COMPEX_RL100ATX 0x2011
|
||||
#define PCI_VENDOR_ID_KTI 0x8e2e
|
||||
#define PCI_DEVICE_ID_KTI_ET32P2 0x3000
|
||||
#define PCI_VENDOR_ID_NETVIN 0x4a14
|
||||
#define PCI_DEVICE_ID_NETVIN_NV5000SC 0x5000
|
||||
#define PCI_VENDOR_ID_3COM 0x10b7
|
||||
#define PCI_DEVICE_ID_3COM_3C590 0x5900
|
||||
#define PCI_DEVICE_ID_3COM_3C595 0x5950
|
||||
#define PCI_DEVICE_ID_3COM_3C595_1 0x5951
|
||||
#define PCI_DEVICE_ID_3COM_3C595_2 0x5952
|
||||
#define PCI_DEVICE_ID_3COM_3C900TPO 0x9000
|
||||
#define PCI_DEVICE_ID_3COM_3C900COMBO 0x9001
|
||||
#define PCI_DEVICE_ID_3COM_3C905TX 0x9050
|
||||
#define PCI_DEVICE_ID_3COM_3C905T4 0x9051
|
||||
#define PCI_DEVICE_ID_3COM_3C905B_TX 0x9055
|
||||
#define PCI_DEVICE_ID_3COM_3C905C_TXM 0x9200
|
||||
#define PCI_VENDOR_ID_INTEL 0x8086
|
||||
#define PCI_DEVICE_ID_INTEL_82557 0x1229
|
||||
#define PCI_DEVICE_ID_INTEL_82559ER 0x1209
|
||||
#define PCI_DEVICE_ID_INTEL_ID1029 0x1029
|
||||
#define PCI_DEVICE_ID_INTEL_ID1030 0x1030
|
||||
#define PCI_DEVICE_ID_INTEL_82562 0x2449
|
||||
#define PCI_VENDOR_ID_AMD 0x1022
|
||||
#define PCI_DEVICE_ID_AMD_LANCE 0x2000
|
||||
#define PCI_VENDOR_ID_AMD_HOMEPNA 0x1022
|
||||
#define PCI_DEVICE_ID_AMD_HOMEPNA 0x2001
|
||||
#define PCI_VENDOR_ID_SMC_1211 0x1113
|
||||
#define PCI_DEVICE_ID_SMC_1211 0x1211
|
||||
#define PCI_VENDOR_ID_DEC 0x1011
|
||||
#define PCI_DEVICE_ID_DEC_TULIP 0x0002
|
||||
#define PCI_DEVICE_ID_DEC_TULIP_FAST 0x0009
|
||||
#define PCI_DEVICE_ID_DEC_TULIP_PLUS 0x0014
|
||||
#define PCI_DEVICE_ID_DEC_21142 0x0019
|
||||
#define PCI_VENDOR_ID_SMC 0x10B8
|
||||
#ifndef PCI_DEVICE_ID_SMC_EPIC100
|
||||
# define PCI_DEVICE_ID_SMC_EPIC100 0x0005
|
||||
#endif
|
||||
#define PCI_VENDOR_ID_MACRONIX 0x10d9
|
||||
#define PCI_DEVICE_ID_MX987x5 0x0531
|
||||
#define PCI_VENDOR_ID_LINKSYS 0x11AD
|
||||
#define PCI_DEVICE_ID_LC82C115 0xC115
|
||||
#define PCI_VENDOR_ID_VIATEC 0x1106
|
||||
#define PCI_DEVICE_ID_VIA_RHINE_I 0x3043
|
||||
#define PCI_DEVICE_ID_VIA_VT6102 0x3065
|
||||
#define PCI_DEVICE_ID_VIA_86C100A 0x6100
|
||||
#define PCI_VENDOR_ID_DAVICOM 0x1282
|
||||
#define PCI_DEVICE_ID_DM9009 0x9009
|
||||
#define PCI_DEVICE_ID_DM9102 0x9102
|
||||
#define PCI_VENDOR_ID_SIS 0x1039
|
||||
#define PCI_DEVICE_ID_SIS900 0x0900
|
||||
#define PCI_DEVICE_ID_SIS7016 0x7016
|
||||
#define PCI_VENDOR_ID_DLINK 0x1186
|
||||
#define PCI_DEVICE_ID_DFE530TXP 0x1300
|
||||
|
||||
struct pci_device {
|
||||
unsigned short vendor, dev_id;
|
||||
const char *name;
|
||||
unsigned int membase;
|
||||
unsigned short ioaddr;
|
||||
unsigned char devfn;
|
||||
unsigned char bus;
|
||||
};
|
||||
|
||||
extern void eth_pci_init(struct pci_device *);
|
||||
|
||||
extern int pcibios_read_config_byte(unsigned int bus, unsigned int device_fn, unsigned int where, unsigned char *value);
|
||||
extern int pcibios_write_config_byte (unsigned int bus, unsigned int device_fn, unsigned int where, unsigned char value);
|
||||
extern int pcibios_read_config_word(unsigned int bus, unsigned int device_fn, unsigned int where, unsigned short *value);
|
||||
extern int pcibios_write_config_word (unsigned int bus, unsigned int device_fn, unsigned int where, unsigned short value);
|
||||
extern int pcibios_write_config_dword(unsigned int bus, unsigned int device_fn, unsigned int where, unsigned int value);
|
||||
#endif /* PCI_H */
|
||||
734
src/etherboot/rarp.c
Normal file
734
src/etherboot/rarp.c
Normal file
|
|
@ -0,0 +1,734 @@
|
|||
#include "etherboot.h"
|
||||
#include "nic.h"
|
||||
|
||||
static unsigned long xid;
|
||||
|
||||
#define eth_poll() nic.poll(&nic)
|
||||
#define eth_transmit(a,b,c,d) nic.transmit(&nic,a,b,c, (char *) d)
|
||||
|
||||
int decode_rfc1533(unsigned char *p, int block, int len, int eof)
|
||||
{
|
||||
return(-1); // don't support it yet, just define it!
|
||||
}
|
||||
|
||||
#define NO_DHCP_SUPPORT
|
||||
#define EMERGENCYDISKBOOT
|
||||
|
||||
#define getchar() ttys0_rx_char()
|
||||
|
||||
static const unsigned char broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
static unsigned long netmask;
|
||||
|
||||
struct arptable_t arptable[MAX_ARP];
|
||||
|
||||
struct bootpd_t bootp_data;
|
||||
|
||||
/***************************************************************************
|
||||
getdec, a simple sort of atoi
|
||||
***************************************************************************/
|
||||
int getdec(char **ptr)
|
||||
{
|
||||
char *p = *ptr;
|
||||
int ret=0;
|
||||
if ((*p < '0') || (*p > '9')) return(-1);
|
||||
while ((*p >= '0') && (*p <= '9')) {
|
||||
ret = ret*10 + (*p - '0');
|
||||
p++;
|
||||
}
|
||||
*ptr = p;
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
STRCASECMP (not entirely correct, but this will do for our purposes)
|
||||
**************************************************************************/
|
||||
int strcasecmp(char *a, char *b)
|
||||
{
|
||||
while (*a && *b && (*a & ~0x20) == (*b & ~0x20)) {a++; b++; }
|
||||
return((*a & ~0x20) - (*b & ~0x20));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
DEFAULT_NETMASK - Return default netmask for IP address
|
||||
**************************************************************************/
|
||||
static inline unsigned long default_netmask(void)
|
||||
{
|
||||
int net = ntohl(arptable[ARP_CLIENT].ipaddr.s_addr) >> 24;
|
||||
if (net <= 127)
|
||||
return(htonl(0xff000000));
|
||||
else if (net < 192)
|
||||
return(htonl(0xffff0000));
|
||||
else
|
||||
return(htonl(0xffffff00));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
IPCHKSUM - Checksum IP Header
|
||||
**************************************************************************/
|
||||
static unsigned short ipchksum(unsigned short *ip, int len)
|
||||
{
|
||||
unsigned long sum = 0;
|
||||
len >>= 1;
|
||||
while (len--) {
|
||||
sum += *(ip++);
|
||||
if (sum > 0xFFFF)
|
||||
sum -= 0xFFFF;
|
||||
}
|
||||
return((~sum) & 0x0000FFFF);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
RFC951_SLEEP - sleep for expotentially longer times
|
||||
**************************************************************************/
|
||||
void rfc951_sleep(int exp)
|
||||
{
|
||||
static long seed = 0;
|
||||
long q;
|
||||
unsigned long tmo;
|
||||
|
||||
#ifdef BACKOFF_LIMIT
|
||||
if (exp > BACKOFF_LIMIT)
|
||||
exp = BACKOFF_LIMIT;
|
||||
#endif
|
||||
if (!seed) /* Initialize linear congruential generator */
|
||||
seed = currticks() + *(long *)&arptable[ARP_CLIENT].node
|
||||
+ ((short *)arptable[ARP_CLIENT].node)[2];
|
||||
/* simplified version of the LCG given in Bruce Scheier's
|
||||
"Applied Cryptography" */
|
||||
q = seed/53668;
|
||||
if ((seed = 40014*(seed-53668*q) - 12211*q) < 0) seed += 2147483563l;
|
||||
/* compute mask */
|
||||
for (tmo = 63; tmo <= 60*TICKS_PER_SEC && --exp > 0; tmo = 2*tmo+1);
|
||||
/* sleep */
|
||||
printk("<sleep>\n");
|
||||
for (tmo = (tmo&seed)+currticks(); currticks() < tmo; )
|
||||
return;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
AWAIT_REPLY - Wait until we get a response for our request
|
||||
**************************************************************************/
|
||||
int await_reply(int type, int ival, void *ptr, int timeout)
|
||||
{
|
||||
unsigned long time;
|
||||
struct iphdr *ip;
|
||||
struct udphdr *udp;
|
||||
struct arprequest *arpreply;
|
||||
struct bootp_t *bootpreply;
|
||||
struct rpc_t *rpc;
|
||||
unsigned short ptype;
|
||||
|
||||
unsigned int protohdrlen = ETH_HLEN + sizeof(struct iphdr) +
|
||||
sizeof(struct udphdr);
|
||||
time = timeout + currticks();
|
||||
/* The timeout check is done below. The timeout is only checked if
|
||||
* there is no packet in the Rx queue. This assumes that eth_poll()
|
||||
* needs a negligible amount of time. */
|
||||
for (;;) {
|
||||
if (eth_poll()) { /* We have something! */
|
||||
/* Check for ARP - No IP hdr */
|
||||
if (nic.packetlen >= ETH_HLEN) {
|
||||
ptype = ((unsigned short) nic.packet[12]) << 8
|
||||
| ((unsigned short) nic.packet[13]);
|
||||
} else continue; /* what else could we do with it? */
|
||||
if ((nic.packetlen >= ETH_HLEN +
|
||||
sizeof(struct arprequest)) &&
|
||||
(ptype == ARP) ) {
|
||||
unsigned long tmp;
|
||||
|
||||
arpreply = (struct arprequest *)
|
||||
&nic.packet[ETH_HLEN];
|
||||
if ((arpreply->opcode == htons(ARP_REPLY)) &&
|
||||
!memcmp(arpreply->sipaddr, ptr, sizeof(in_addr)) &&
|
||||
(type == AWAIT_ARP)) {
|
||||
memcpy(arptable[ival].node, arpreply->shwaddr, ETH_ALEN);
|
||||
return(1);
|
||||
}
|
||||
memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
|
||||
if ((arpreply->opcode == htons(ARP_REQUEST)) &&
|
||||
(tmp == arptable[ARP_CLIENT].ipaddr.s_addr)) {
|
||||
arpreply->opcode = htons(ARP_REPLY);
|
||||
memcpy(arpreply->tipaddr, arpreply->sipaddr, sizeof(in_addr));
|
||||
memcpy(arpreply->thwaddr, arpreply->shwaddr, ETH_ALEN);
|
||||
memcpy(arpreply->sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr));
|
||||
memcpy(arpreply->shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
|
||||
eth_transmit(arpreply->thwaddr, ARP,
|
||||
sizeof(struct arprequest),
|
||||
(char *) arpreply);
|
||||
#ifdef MDEBUG
|
||||
memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
|
||||
printf("Sent ARP reply to: %I\n",tmp);
|
||||
#endif /* MDEBUG */
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type == AWAIT_QDRAIN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check for RARP - No IP hdr */
|
||||
if ((type == AWAIT_RARP) &&
|
||||
(nic.packetlen >= ETH_HLEN +
|
||||
sizeof(struct arprequest)) &&
|
||||
(ptype == RARP)) {
|
||||
arpreply = (struct arprequest *)
|
||||
&nic.packet[ETH_HLEN];
|
||||
if ((arpreply->opcode == htons(RARP_REPLY)) &&
|
||||
!memcmp(arpreply->thwaddr, ptr, ETH_ALEN)) {
|
||||
memcpy(arptable[ARP_SERVER].node, arpreply->shwaddr, ETH_ALEN);
|
||||
memcpy(& arptable[ARP_SERVER].ipaddr, arpreply->sipaddr, sizeof(in_addr));
|
||||
memcpy(& arptable[ARP_CLIENT].ipaddr, arpreply->tipaddr, sizeof(in_addr));
|
||||
return(1);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Anything else has IP header */
|
||||
if ((nic.packetlen < protohdrlen) ||
|
||||
(ptype != IP) ) continue;
|
||||
ip = (struct iphdr *)&nic.packet[ETH_HLEN];
|
||||
if ((ip->verhdrlen != 0x45) ||
|
||||
ipchksum((unsigned short *)ip, sizeof(struct iphdr)) ||
|
||||
(ip->protocol != IP_UDP)) continue;
|
||||
udp = (struct udphdr *)&nic.packet[ETH_HLEN +
|
||||
sizeof(struct iphdr)];
|
||||
|
||||
/* BOOTP ? */
|
||||
bootpreply = (struct bootp_t *)&nic.packet[ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr)];
|
||||
if ((type == AWAIT_BOOTP) &&
|
||||
(nic.packetlen >= (ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr) +
|
||||
#ifdef NO_DHCP_SUPPORT
|
||||
sizeof(struct bootp_t))) &&
|
||||
#else
|
||||
sizeof(struct bootp_t))-DHCP_OPT_LEN) &&
|
||||
#endif /* NO_DHCP_SUPPORT */
|
||||
(udp->dest == htons(BOOTP_CLIENT)) &&
|
||||
(bootpreply->bp_op == BOOTP_REPLY) &&
|
||||
(bootpreply->bp_xid == xid) &&
|
||||
(memcmp(broadcast, bootpreply->bp_hwaddr, ETH_ALEN) ==0 ||
|
||||
memcmp(arptable[ARP_CLIENT].node, bootpreply->bp_hwaddr, ETH_ALEN) == 0)) {
|
||||
arptable[ARP_CLIENT].ipaddr.s_addr =
|
||||
bootpreply->bp_yiaddr.s_addr;
|
||||
#ifndef NO_DHCP_SUPPORT
|
||||
dhcp_addr.s_addr = bootpreply->bp_yiaddr.s_addr;
|
||||
#endif /* NO_DHCP_SUPPORT */
|
||||
netmask = default_netmask();
|
||||
arptable[ARP_SERVER].ipaddr.s_addr =
|
||||
bootpreply->bp_siaddr.s_addr;
|
||||
memset(arptable[ARP_SERVER].node, 0, ETH_ALEN); /* Kill arp */
|
||||
arptable[ARP_GATEWAY].ipaddr.s_addr =
|
||||
bootpreply->bp_giaddr.s_addr;
|
||||
memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN); /* Kill arp */
|
||||
/* bootpreply->bp_file will be copied to KERNEL_BUF in the memcpy */
|
||||
memcpy((char *)BOOTP_DATA_ADDR, (char *)bootpreply, sizeof(struct bootpd_t));
|
||||
decode_rfc1533(BOOTP_DATA_ADDR->bootp_reply.bp_vend,
|
||||
#ifdef NO_DHCP_SUPPORT
|
||||
0, BOOTP_VENDOR_LEN + MAX_BOOTP_EXTLEN, 1);
|
||||
#else
|
||||
0, DHCP_OPT_LEN + MAX_BOOTP_EXTLEN, 1);
|
||||
#endif /* NO_DHCP_SUPPORT */
|
||||
#ifdef REQUIRE_VCI_ETHERBOOT
|
||||
if (!vci_etherboot)
|
||||
return (0);
|
||||
#endif
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
#ifdef DOWNLOAD_PROTO_TFTP
|
||||
/* TFTP ? */
|
||||
if ((type == AWAIT_TFTP) &&
|
||||
(ntohs(udp->dest) == ival)) return(1);
|
||||
#endif /* DOWNLOAD_PROTO_TFTP */
|
||||
|
||||
#ifdef DOWNLOAD_PROTO_NFS
|
||||
/* RPC ? */
|
||||
rpc = (struct rpc_t *)&nic.packet[ETH_HLEN];
|
||||
if ((type == AWAIT_RPC) &&
|
||||
(ntohs(udp->dest) == ival) &&
|
||||
(*(unsigned long *)ptr == ntohl(rpc->u.reply.id)) &&
|
||||
(ntohl(rpc->u.reply.type) == MSG_REPLY)) {
|
||||
return (1);
|
||||
}
|
||||
#endif /* DOWNLOAD_PROTO_NFS */
|
||||
|
||||
} else {
|
||||
/* Check for abort key only if the Rx queue is empty -
|
||||
* as long as we have something to process, don't
|
||||
* assume that something failed. It is unlikely that
|
||||
* we have no processing time left between packets. */
|
||||
if (iskey() && (getchar() == ESC))
|
||||
#ifdef EMERGENCYDISKBOOT
|
||||
return(-1);
|
||||
#else
|
||||
longjmp(jmp_bootmenu, -1);
|
||||
#endif
|
||||
/* Do the timeout after at least a full queue walk. */
|
||||
if ((timeout == 0) || (currticks() > time)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
RARP - Get my IP address and load information
|
||||
**************************************************************************/
|
||||
int rarp(void)
|
||||
{
|
||||
int retry;
|
||||
|
||||
/* arp and rarp requests share the same packet structure. */
|
||||
struct arprequest rarpreq;
|
||||
|
||||
memset(&rarpreq, 0, sizeof(rarpreq));
|
||||
|
||||
rarpreq.hwtype = htons(1);
|
||||
rarpreq.protocol = htons(IP);
|
||||
rarpreq.hwlen = ETH_ALEN;
|
||||
rarpreq.protolen = 4;
|
||||
rarpreq.opcode = htons(RARP_REQUEST);
|
||||
memcpy(&rarpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
|
||||
/* sipaddr is already zeroed out */
|
||||
memcpy(&rarpreq.thwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
|
||||
/* tipaddr is already zeroed out */
|
||||
|
||||
for (retry = 0; retry < MAX_ARP_RETRIES; rfc951_sleep(++retry)) {
|
||||
eth_transmit(broadcast, RARP, sizeof(rarpreq), &rarpreq);
|
||||
|
||||
if (await_reply(AWAIT_RARP, 0, rarpreq.shwaddr, TIMEOUT))
|
||||
break;
|
||||
}
|
||||
|
||||
if (retry < MAX_ARP_RETRIES) {
|
||||
(void)sprintf(KERNEL_BUF, DEFAULT_KERNELPATH, arptable[ARP_CLIENT].ipaddr);
|
||||
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
UDP_TRANSMIT - Send a UDP datagram
|
||||
**************************************************************************/
|
||||
int udp_transmit(unsigned long destip, unsigned int srcsock,
|
||||
unsigned int destsock, int len, const void *buf)
|
||||
{
|
||||
struct iphdr *ip;
|
||||
struct udphdr *udp;
|
||||
struct arprequest arpreq;
|
||||
int arpentry, i;
|
||||
int retry;
|
||||
|
||||
ip = (struct iphdr *)buf;
|
||||
udp = (struct udphdr *)((char *)buf + sizeof(struct iphdr));
|
||||
ip->verhdrlen = 0x45;
|
||||
ip->service = 0;
|
||||
ip->len = htons(len);
|
||||
ip->ident = 0;
|
||||
ip->frags = 0;
|
||||
ip->ttl = 60;
|
||||
ip->protocol = IP_UDP;
|
||||
ip->chksum = 0;
|
||||
ip->src.s_addr = arptable[ARP_CLIENT].ipaddr.s_addr;
|
||||
ip->dest.s_addr = destip;
|
||||
ip->chksum = ipchksum((unsigned short *)buf, sizeof(struct iphdr));
|
||||
udp->src = htons(srcsock);
|
||||
udp->dest = htons(destsock);
|
||||
udp->len = htons(len - sizeof(struct iphdr));
|
||||
udp->chksum = 0;
|
||||
if (destip == IP_BROADCAST) {
|
||||
eth_transmit(broadcast, IP, len, buf);
|
||||
} else {
|
||||
if (((destip & netmask) !=
|
||||
(arptable[ARP_CLIENT].ipaddr.s_addr & netmask)) &&
|
||||
arptable[ARP_GATEWAY].ipaddr.s_addr)
|
||||
destip = arptable[ARP_GATEWAY].ipaddr.s_addr;
|
||||
for(arpentry = 0; arpentry<MAX_ARP; arpentry++)
|
||||
if (arptable[arpentry].ipaddr.s_addr == destip) break;
|
||||
if (arpentry == MAX_ARP) {
|
||||
printk("%I is not in my arp table!\n", destip);
|
||||
return(0);
|
||||
}
|
||||
for (i = 0; i < ETH_ALEN; i++)
|
||||
if (arptable[arpentry].node[i])
|
||||
break;
|
||||
if (i == ETH_ALEN) { /* Need to do arp request */
|
||||
arpreq.hwtype = htons(1);
|
||||
arpreq.protocol = htons(IP);
|
||||
arpreq.hwlen = ETH_ALEN;
|
||||
arpreq.protolen = 4;
|
||||
arpreq.opcode = htons(ARP_REQUEST);
|
||||
memcpy(arpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
|
||||
memcpy(arpreq.sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr));
|
||||
memset(arpreq.thwaddr, 0, ETH_ALEN);
|
||||
memcpy(arpreq.tipaddr, &destip, sizeof(in_addr));
|
||||
for (retry = 1; retry <= MAX_ARP_RETRIES; retry++) {
|
||||
eth_transmit(broadcast, ARP, sizeof(arpreq),
|
||||
&arpreq);
|
||||
if (await_reply(AWAIT_ARP, arpentry,
|
||||
arpreq.tipaddr, TIMEOUT)) goto xmit;
|
||||
rfc951_sleep(retry);
|
||||
/* We have slept for a while - the packet may
|
||||
* have arrived by now. If not, we have at
|
||||
* least some room in the Rx buffer for the
|
||||
* next reply. */
|
||||
if (await_reply(AWAIT_ARP, arpentry,
|
||||
arpreq.tipaddr, 0)) goto xmit;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
xmit:
|
||||
eth_transmit(arptable[arpentry].node, IP, len, buf);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
TFTP - Download extended BOOTP data, or kernel image
|
||||
**************************************************************************/
|
||||
int tftp(const char *name, int (*fnc)(unsigned char *, int, int, int))
|
||||
{
|
||||
int retry = 0;
|
||||
static unsigned short iport = 2000;
|
||||
unsigned short oport;
|
||||
unsigned short len, block = 0, prevblock = 0;
|
||||
int bcounter = 0;
|
||||
struct tftp_t *tr;
|
||||
struct tftpreq_t tp;
|
||||
int rc;
|
||||
int packetsize = TFTP_DEFAULTSIZE_PACKET;
|
||||
|
||||
/* Clear out the Rx queue first. It contains nothing of interest,
|
||||
* except possibly ARP requests from the DHCP/TFTP server. We use
|
||||
* polling throughout Etherboot, so some time may have passed since we
|
||||
* last polled the receive queue, which may now be filled with
|
||||
* broadcast packets. This will cause the reply to the packets we are
|
||||
* about to send to be lost immediately. Not very clever. */
|
||||
await_reply(AWAIT_QDRAIN, 0, NULL, 0);
|
||||
|
||||
tp.opcode = htons(TFTP_RRQ);
|
||||
/* Warning: the following assumes the layout of bootp_t.
|
||||
But that's fixed by the IP, UDP and BOOTP specs. */
|
||||
len = sizeof(tp.ip) + sizeof(tp.udp) + sizeof(tp.opcode) +
|
||||
sprintf((char *)tp.u.rrq, "%s%coctet%cblksize%c%d",
|
||||
name, 0, 0, 0, TFTP_MAX_PACKET) + 1;
|
||||
if (!udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, ++iport,
|
||||
TFTP_PORT, len, &tp))
|
||||
return (0);
|
||||
for (;;)
|
||||
{
|
||||
#ifdef CONGESTED
|
||||
if (!await_reply(AWAIT_TFTP, iport, NULL, (block ? TFTP_REXMT : TIMEOUT)))
|
||||
#else
|
||||
if (!await_reply(AWAIT_TFTP, iport, NULL, TIMEOUT))
|
||||
#endif
|
||||
{
|
||||
if (!block && retry++ < MAX_TFTP_RETRIES)
|
||||
{ /* maybe initial request was lost */
|
||||
rfc951_sleep(retry);
|
||||
if (!udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
|
||||
++iport, TFTP_PORT, len, &tp))
|
||||
return (0);
|
||||
continue;
|
||||
}
|
||||
#ifdef CONGESTED
|
||||
if (block && ((retry += TFTP_REXMT) < TFTP_TIMEOUT))
|
||||
{ /* we resend our last ack */
|
||||
#ifdef MDEBUG
|
||||
printk("<REXMT>\n");
|
||||
#endif
|
||||
udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
|
||||
iport, oport,
|
||||
TFTP_MIN_PACKET, &tp);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
break; /* timeout */
|
||||
}
|
||||
tr = (struct tftp_t *)&nic.packet[ETH_HLEN];
|
||||
if (tr->opcode == ntohs(TFTP_ERROR))
|
||||
{
|
||||
printk("TFTP error %d (%s)\n",
|
||||
ntohs(tr->u.err.errcode),
|
||||
tr->u.err.errmsg);
|
||||
break;
|
||||
}
|
||||
|
||||
if (tr->opcode == ntohs(TFTP_OACK)) {
|
||||
char *p = tr->u.oack.data, *e;
|
||||
|
||||
if (prevblock) /* shouldn't happen */
|
||||
continue; /* ignore it */
|
||||
len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 2;
|
||||
if (len > TFTP_MAX_PACKET)
|
||||
goto noak;
|
||||
e = p + len;
|
||||
while (*p != '\000' && p < e) {
|
||||
if (!strcasecmp("blksize", p)) {
|
||||
p += 8;
|
||||
if ((packetsize = getdec(&p)) <
|
||||
TFTP_DEFAULTSIZE_PACKET)
|
||||
goto noak;
|
||||
while (p < e && *p) p++;
|
||||
if (p < e)
|
||||
p++;
|
||||
}
|
||||
else {
|
||||
noak:
|
||||
tp.opcode = htons(TFTP_ERROR);
|
||||
tp.u.err.errcode = 8;
|
||||
/*
|
||||
* Warning: the following assumes the layout of bootp_t.
|
||||
* But that's fixed by the IP, UDP and BOOTP specs.
|
||||
*/
|
||||
len = sizeof(tp.ip) + sizeof(tp.udp) + sizeof(tp.opcode) + sizeof(tp.u.err.errcode) +
|
||||
sprintf((char *)tp.u.err.errmsg,
|
||||
"RFC1782 error") + 1;
|
||||
udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
|
||||
iport, ntohs(tr->udp.src),
|
||||
len, &tp);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
if (p > e)
|
||||
goto noak;
|
||||
block = tp.u.ack.block = 0; /* this ensures, that */
|
||||
/* the packet does not get */
|
||||
/* processed as data! */
|
||||
}
|
||||
else if (tr->opcode == htons(TFTP_DATA)) {
|
||||
len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 4;
|
||||
if (len > packetsize) /* shouldn't happen */
|
||||
continue; /* ignore it */
|
||||
block = ntohs(tp.u.ack.block = tr->u.data.block); }
|
||||
else /* neither TFTP_OACK nor TFTP_DATA */
|
||||
break;
|
||||
|
||||
if ((block || bcounter) && (block != prevblock+1)) {
|
||||
/* Block order should be continuous */
|
||||
tp.u.ack.block = htons(block = prevblock);
|
||||
}
|
||||
tp.opcode = htons(TFTP_ACK);
|
||||
oport = ntohs(tr->udp.src);
|
||||
udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, iport,
|
||||
oport, TFTP_MIN_PACKET, &tp); /* ack */
|
||||
if ((unsigned short)(block-prevblock) != 1) {
|
||||
/* Retransmission or OACK, don't process via callback
|
||||
* and don't change the value of prevblock. */
|
||||
continue;
|
||||
}
|
||||
prevblock = block;
|
||||
retry = 0; /* It's the right place to zero the timer? */
|
||||
if ((rc = fnc(tr->u.data.download,
|
||||
++bcounter, len, len < packetsize)) >= 0)
|
||||
return(rc);
|
||||
if (len < packetsize) /* End of data */
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int retry = 0;
|
||||
static unsigned short iport = 2000;
|
||||
unsigned short oport;
|
||||
unsigned short len, block = 0, prevblock = 0;
|
||||
int bcounter = 0;
|
||||
struct tftp_t *tr;
|
||||
struct tftpreq_t tp;
|
||||
int rc;
|
||||
int packetsize = TFTP_DEFAULTSIZE_PACKET;
|
||||
|
||||
int tftp_init(const char *name)
|
||||
{
|
||||
retry = 0;
|
||||
iport = 2000;
|
||||
block = 0;
|
||||
prevblock = 0;
|
||||
bcounter = 0;
|
||||
packetsize = TFTP_DEFAULTSIZE_PACKET;
|
||||
|
||||
/* Clear out the Rx queue first. It contains nothing of interest,
|
||||
* except possibly ARP requests from the DHCP/TFTP server. We use
|
||||
* polling throughout Etherboot, so some time may have passed since we
|
||||
* last polled the receive queue, which may now be filled with
|
||||
* broadcast packets. This will cause the reply to the packets we are
|
||||
* about to send to be lost immediately. Not very clever. */
|
||||
await_reply(AWAIT_QDRAIN, 0, NULL, 0);
|
||||
|
||||
tp.opcode = htons(TFTP_RRQ);
|
||||
/* Warning: the following assumes the layout of bootp_t.
|
||||
But that's fixed by the IP, UDP and BOOTP specs. */
|
||||
len = sizeof(tp.ip) + sizeof(tp.udp) + sizeof(tp.opcode) +
|
||||
sprintf((char *)tp.u.rrq, "%s%coctet%cblksize%c%d",
|
||||
name, 0, 0, 0, TFTP_MAX_PACKET) + 1;
|
||||
if (!udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, ++iport,
|
||||
TFTP_PORT, len, &tp))
|
||||
return (-1);
|
||||
#ifdef CONGESTED
|
||||
while (!await_reply(AWAIT_TFTP, iport, NULL, (block ? TFTP_REXMT : TIMEOUT)))
|
||||
#else
|
||||
while (!await_reply(AWAIT_TFTP, iport, NULL, TIMEOUT))
|
||||
#endif
|
||||
{
|
||||
if (!block && retry++ < MAX_TFTP_RETRIES)
|
||||
{ /* maybe initial request was lost */
|
||||
rfc951_sleep(retry);
|
||||
if (!udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
|
||||
++iport, TFTP_PORT, len, &tp))
|
||||
return (-1);
|
||||
continue;
|
||||
}
|
||||
#ifdef CONGESTED
|
||||
if (block && ((retry += TFTP_REXMT) < TFTP_TIMEOUT))
|
||||
{ /* we resend our last ack */
|
||||
#ifdef MDEBUG
|
||||
printk("<REXMT>\n");
|
||||
#endif
|
||||
udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
|
||||
iport, oport,
|
||||
TFTP_MIN_PACKET, &tp);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
break; /* timeout */
|
||||
}
|
||||
|
||||
// we have recieved reply. see if it's any good.
|
||||
|
||||
tr = (struct tftp_t *)&nic.packet[ETH_HLEN];
|
||||
if (tr->opcode == ntohs(TFTP_ERROR)) {
|
||||
printk("TFTP error %d (%s)\n",
|
||||
ntohs(tr->u.err.errcode),
|
||||
tr->u.err.errmsg);
|
||||
|
||||
return(-ntohs(tr->u.err.errcode));
|
||||
}
|
||||
|
||||
if (tr->opcode == ntohs(TFTP_OACK)) {
|
||||
char *p = tr->u.oack.data, *e;
|
||||
|
||||
if (prevblock) /* shouldn't happen */
|
||||
return(-1); /* ignore it */
|
||||
len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 2;
|
||||
if (len > TFTP_MAX_PACKET)
|
||||
goto noak;
|
||||
e = p + len;
|
||||
while (*p != '\000' && p < e) {
|
||||
if (!strcasecmp("blksize", p)) {
|
||||
p += 8;
|
||||
if ((packetsize = getdec(&p)) <
|
||||
TFTP_DEFAULTSIZE_PACKET)
|
||||
goto noak;
|
||||
while (p < e && *p) p++;
|
||||
if (p < e)
|
||||
p++;
|
||||
}
|
||||
else {
|
||||
noak:
|
||||
tp.opcode = htons(TFTP_ERROR);
|
||||
tp.u.err.errcode = 8;
|
||||
/*
|
||||
* Warning: the following assumes the layout of bootp_t.
|
||||
* But that's fixed by the IP, UDP and BOOTP specs.
|
||||
*/
|
||||
len = sizeof(tp.ip) + sizeof(tp.udp) + sizeof(tp.opcode) + sizeof(tp.u.err.errcode) +
|
||||
sprintf((char *)tp.u.err.errmsg,
|
||||
"RFC1782 error") + 1;
|
||||
udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
|
||||
iport, ntohs(tr->udp.src),
|
||||
len, &tp);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
if (p > e)
|
||||
goto noak;
|
||||
block = tp.u.ack.block = 0; /* this ensures, that */
|
||||
/* the packet does not get */
|
||||
/* processed as data! */
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
int tftp_fetchone(char *buffer)
|
||||
{
|
||||
/* Clear out the Rx queue first. It contains nothing of interest,
|
||||
* except possibly ARP requests from the DHCP/TFTP server. We use
|
||||
* polling throughout Etherboot, so some time may have passed since we
|
||||
* last polled the receive queue, which may now be filled with
|
||||
* broadcast packets. This will cause the reply to the packets we are
|
||||
* about to send to be lost immediately. Not very clever. */
|
||||
retry:
|
||||
await_reply(AWAIT_QDRAIN, 0, NULL, 0);
|
||||
|
||||
tp.opcode = htons(TFTP_ACK);
|
||||
oport = ntohs(tr->udp.src);
|
||||
udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, iport,
|
||||
oport, TFTP_MIN_PACKET, &tp); /* ack */
|
||||
|
||||
#ifdef CONGESTED
|
||||
while (!await_reply(AWAIT_TFTP, iport, NULL, (block ? TFTP_REXMT : TIMEOUT)))
|
||||
#else
|
||||
while (!await_reply(AWAIT_TFTP, iport, NULL, TIMEOUT))
|
||||
#endif
|
||||
{
|
||||
if (!block && retry++ < MAX_TFTP_RETRIES)
|
||||
{ /* maybe initial request was lost */
|
||||
rfc951_sleep(retry);
|
||||
if (!udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
|
||||
++iport, TFTP_PORT, len, &tp))
|
||||
return (-1);
|
||||
continue;
|
||||
}
|
||||
#ifdef CONGESTED
|
||||
if (block && ((retry += TFTP_REXMT) < TFTP_TIMEOUT))
|
||||
{ /* we resend our last ack */
|
||||
#ifdef MDEBUG
|
||||
printk("<REXMT>\n");
|
||||
#endif
|
||||
udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
|
||||
iport, oport,
|
||||
TFTP_MIN_PACKET, &tp);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
break; /* timeout */
|
||||
}
|
||||
|
||||
tr = (struct tftp_t *)&nic.packet[ETH_HLEN];
|
||||
if (tr->opcode == ntohs(TFTP_ERROR))
|
||||
{
|
||||
printk("TFTP error %d (%s)\n",
|
||||
ntohs(tr->u.err.errcode),
|
||||
tr->u.err.errmsg);
|
||||
return(-tr->u.err.errcode);
|
||||
}
|
||||
|
||||
if (tr->opcode == ntohs(TFTP_OACK))
|
||||
goto retry; // session is already started! try again.
|
||||
|
||||
else if (tr->opcode == htons(TFTP_DATA)) {
|
||||
len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 4;
|
||||
if (len > packetsize) /* shouldn't happen */
|
||||
goto retry; /* bad thing, skip it and try again! */
|
||||
block = ntohs(tp.u.ack.block = tr->u.data.block);
|
||||
|
||||
} else /* neither TFTP_OACK nor TFTP_DATA */
|
||||
goto retry; // whatever it is, it's invalid! try again.
|
||||
|
||||
if ((block || bcounter) && (block != prevblock+1)) {
|
||||
/* Block order should be continuous */
|
||||
tp.u.ack.block = htons(block = prevblock);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
prevblock = block;
|
||||
retry = 0; /* It's the right place to zero the timer? */
|
||||
|
||||
|
||||
memcpy(buffer,tr->u.data.download, len);
|
||||
return(len);
|
||||
}
|
||||
1073
src/etherboot/sis900.c
Normal file
1073
src/etherboot/sis900.c
Normal file
File diff suppressed because it is too large
Load diff
365
src/etherboot/sis900.h
Normal file
365
src/etherboot/sis900.h
Normal file
|
|
@ -0,0 +1,365 @@
|
|||
/* -*- Mode:C; c-basic-offset:4; -*- */
|
||||
|
||||
/* Definitions for SiS ethernet controllers including 7014/7016 and 900
|
||||
* References:
|
||||
* SiS 7016 Fast Ethernet PCI Bus 10/100 Mbps LAN Controller with OnNow Support,
|
||||
* preliminary Rev. 1.0 Jan. 14, 1998
|
||||
* SiS 900 Fast Ethernet PCI Bus 10/100 Mbps LAN Single Chip with OnNow Support,
|
||||
* preliminary Rev. 1.0 Nov. 10, 1998
|
||||
* SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution,
|
||||
* preliminary Rev. 1.0 Jan. 18, 1998
|
||||
* http://www.sis.com.tw/support/databook.htm
|
||||
*/
|
||||
|
||||
/* MAC operationl registers of SiS 7016 and SiS 900 ethernet controller */
|
||||
/* The I/O extent, SiS 900 needs 256 bytes of io address */
|
||||
#define SIS900_TOTAL_SIZE 0x100
|
||||
|
||||
/* Symbolic offsets to registers. */
|
||||
enum sis900_registers {
|
||||
cr=0x0, /* Command Register */
|
||||
cfg=0x4, /* Configuration Register */
|
||||
mear=0x8, /* EEPROM Access Register */
|
||||
ptscr=0xc, /* PCI Test Control Register */
|
||||
isr=0x10, /* Interrupt Status Register */
|
||||
imr=0x14, /* Interrupt Mask Register */
|
||||
ier=0x18, /* Interrupt Enable Register */
|
||||
epar=0x18, /* Enhanced PHY Access Register */
|
||||
txdp=0x20, /* Transmit Descriptor Pointer Register */
|
||||
txcfg=0x24, /* Transmit Configuration Register */
|
||||
rxdp=0x30, /* Receive Descriptor Pointer Register */
|
||||
rxcfg=0x34, /* Receive Configuration Register */
|
||||
flctrl=0x38, /* Flow Control Register */
|
||||
rxlen=0x3c, /* Receive Packet Length Register */
|
||||
rfcr=0x48, /* Receive Filter Control Register */
|
||||
rfdr=0x4C, /* Receive Filter Data Register */
|
||||
pmctrl=0xB0, /* Power Management Control Register */
|
||||
pmer=0xB4 /* Power Management Wake-up Event Register */
|
||||
};
|
||||
|
||||
/* Symbolic names for bits in various registers */
|
||||
enum sis900_command_register_bits {
|
||||
RESET = 0x00000100,
|
||||
SWI = 0x00000080,
|
||||
RxRESET = 0x00000020,
|
||||
TxRESET = 0x00000010,
|
||||
RxDIS = 0x00000008,
|
||||
RxENA = 0x00000004,
|
||||
TxDIS = 0x00000002,
|
||||
TxENA = 0x00000001
|
||||
};
|
||||
|
||||
enum sis900_configuration_register_bits {
|
||||
DESCRFMT = 0x00000100, /* 7016 specific */
|
||||
REQALG = 0x00000080,
|
||||
SB = 0x00000040,
|
||||
POW = 0x00000020,
|
||||
EXD = 0x00000010,
|
||||
PESEL = 0x00000008,
|
||||
LPM = 0x00000004,
|
||||
BEM = 0x00000001
|
||||
};
|
||||
|
||||
enum sis900_eeprom_access_reigster_bits {
|
||||
MDC = 0x00000040,
|
||||
MDDIR = 0x00000020,
|
||||
MDIO = 0x00000010, /* 7016 specific */
|
||||
EECS = 0x00000008,
|
||||
EECLK = 0x00000004,
|
||||
EEDO = 0x00000002,
|
||||
EEDI = 0x00000001
|
||||
};
|
||||
|
||||
enum sis900_interrupt_register_bits {
|
||||
WKEVT = 0x10000000,
|
||||
TxPAUSEEND = 0x08000000,
|
||||
TxPAUSE = 0x04000000,
|
||||
TxRCMP = 0x02000000,
|
||||
RxRCMP = 0x01000000,
|
||||
DPERR = 0x00800000,
|
||||
SSERR = 0x00400000,
|
||||
RMABT = 0x00200000,
|
||||
RTABT = 0x00100000,
|
||||
RxSOVR = 0x00010000,
|
||||
HIBERR = 0x00008000,
|
||||
SWINT = 0x00001000,
|
||||
MIBINT = 0x00000800,
|
||||
TxURN = 0x00000400,
|
||||
TxIDLE = 0x00000200,
|
||||
TxERR = 0x00000100,
|
||||
TxDESC = 0x00000080,
|
||||
TxOK = 0x00000040,
|
||||
RxORN = 0x00000020,
|
||||
RxIDLE = 0x00000010,
|
||||
RxEARLY = 0x00000008,
|
||||
RxERR = 0x00000004,
|
||||
RxDESC = 0x00000002,
|
||||
RxOK = 0x00000001
|
||||
};
|
||||
|
||||
enum sis900_interrupt_enable_reigster_bits {
|
||||
IE = 0x00000001
|
||||
};
|
||||
|
||||
/* maximum dma burst fro transmission and receive*/
|
||||
#define MAX_DMA_RANGE 7 /* actually 0 means MAXIMUM !! */
|
||||
#define TxMXDMA_shift 20
|
||||
#define RxMXDMA_shift 20
|
||||
#define TX_DMA_BURST 0
|
||||
#define RX_DMA_BURST 0
|
||||
|
||||
/* transmit FIFO threshholds */
|
||||
#define TX_FILL_THRESH 16 /* 1/4 FIFO size */
|
||||
#define TxFILLT_shift 8
|
||||
#define TxDRNT_shift 0
|
||||
#define TxDRNT_100 48 /* 3/4 FIFO size */
|
||||
#define TxDRNT_10 16 /* 1/2 FIFO size */
|
||||
|
||||
enum sis900_transmit_config_register_bits {
|
||||
TxCSI = 0x80000000,
|
||||
TxHBI = 0x40000000,
|
||||
TxMLB = 0x20000000,
|
||||
TxATP = 0x10000000,
|
||||
TxIFG = 0x0C000000,
|
||||
TxFILLT = 0x00003F00,
|
||||
TxDRNT = 0x0000003F
|
||||
};
|
||||
|
||||
/* recevie FIFO thresholds */
|
||||
#define RxDRNT_shift 1
|
||||
#define RxDRNT_100 16 /* 1/2 FIFO size */
|
||||
#define RxDRNT_10 24 /* 3/4 FIFO size */
|
||||
|
||||
enum sis900_reveive_config_register_bits {
|
||||
RxAEP = 0x80000000,
|
||||
RxARP = 0x40000000,
|
||||
RxATX = 0x10000000,
|
||||
RxAJAB = 0x08000000,
|
||||
RxDRNT = 0x0000007F
|
||||
};
|
||||
|
||||
#define RFAA_shift 28
|
||||
#define RFADDR_shift 16
|
||||
|
||||
enum sis900_receive_filter_control_register_bits {
|
||||
RFEN = 0x80000000,
|
||||
RFAAB = 0x40000000,
|
||||
RFAAM = 0x20000000,
|
||||
RFAAP = 0x10000000,
|
||||
RFPromiscuous = (RFAAB|RFAAM|RFAAP)
|
||||
};
|
||||
|
||||
enum sis900_reveive_filter_data_mask {
|
||||
RFDAT = 0x0000FFFF
|
||||
};
|
||||
|
||||
/* EEPROM Addresses */
|
||||
enum sis900_eeprom_address {
|
||||
EEPROMSignature = 0x00,
|
||||
EEPROMVendorID = 0x02,
|
||||
EEPROMDeviceID = 0x03,
|
||||
EEPROMMACAddr = 0x08,
|
||||
EEPROMChecksum = 0x0b
|
||||
};
|
||||
|
||||
/* The EEPROM commands include the alway-set leading bit. Refer to NM93Cxx datasheet */
|
||||
enum sis900_eeprom_command {
|
||||
EEread = 0x0180,
|
||||
EEwrite = 0x0140,
|
||||
EEerase = 0x01C0,
|
||||
EEwriteEnable = 0x0130,
|
||||
EEwriteDisable = 0x0100,
|
||||
EEeraseAll = 0x0120,
|
||||
EEwriteAll = 0x0110,
|
||||
EEaddrMask = 0x013F,
|
||||
};
|
||||
|
||||
/* Manamgement Data I/O (mdio) frame */
|
||||
#define MIIread 0x6000
|
||||
#define MIIwrite 0x5002
|
||||
#define MIIpmdShift 7
|
||||
#define MIIregShift 2
|
||||
#define MIIcmdLen 16
|
||||
#define MIIcmdShift 16
|
||||
|
||||
/* Buffer Descriptor Status*/
|
||||
enum sis900_buffer_status {
|
||||
OWN = 0x80000000,
|
||||
MORE = 0x40000000,
|
||||
INTR = 0x20000000,
|
||||
SUPCRC = 0x10000000,
|
||||
INCCRC = 0x10000000,
|
||||
OK = 0x08000000,
|
||||
DSIZE = 0x00000FFF
|
||||
};
|
||||
|
||||
/* Status for TX Buffers */
|
||||
enum sis900_tx_buffer_status {
|
||||
ABORT = 0x04000000,
|
||||
UNDERRUN = 0x02000000,
|
||||
NOCARRIER = 0x01000000,
|
||||
DEFERD = 0x00800000,
|
||||
EXCDEFER = 0x00400000,
|
||||
OWCOLL = 0x00200000,
|
||||
EXCCOLL = 0x00100000,
|
||||
COLCNT = 0x000F0000
|
||||
};
|
||||
|
||||
enum sis900_rx_bufer_status {
|
||||
OVERRUN = 0x02000000,
|
||||
DEST = 0x00800000,
|
||||
BCAST = 0x01800000,
|
||||
MCAST = 0x01000000,
|
||||
UNIMATCH = 0x00800000,
|
||||
TOOLONG = 0x00400000,
|
||||
RUNT = 0x00200000,
|
||||
RXISERR = 0x00100000,
|
||||
CRCERR = 0x00080000,
|
||||
FAERR = 0x00040000,
|
||||
LOOPBK = 0x00020000,
|
||||
RXCOL = 0x00010000
|
||||
};
|
||||
|
||||
/* MII register offsets */
|
||||
enum mii_registers {
|
||||
MII_CONTROL = 0x0000,
|
||||
MII_STATUS = 0x0001,
|
||||
MII_PHY_ID0 = 0x0002,
|
||||
MII_PHY_ID1 = 0x0003,
|
||||
MII_ANADV = 0x0004,
|
||||
MII_ANLPAR = 0x0005,
|
||||
MII_ANEXT = 0x0006
|
||||
};
|
||||
|
||||
/* mii registers specific to SiS 900 */
|
||||
enum sis_mii_registers {
|
||||
MII_CONFIG1 = 0x0010,
|
||||
MII_CONFIG2 = 0x0011,
|
||||
MII_STSOUT = 0x0012,
|
||||
MII_MASK = 0x0013
|
||||
};
|
||||
|
||||
/* mii registers specific to AMD 79C901 */
|
||||
enum amd_mii_registers {
|
||||
MII_STATUS_SUMMARY = 0x0018
|
||||
};
|
||||
|
||||
/* mii registers specific to ICS 1893 */
|
||||
enum ics_mii_registers {
|
||||
MII_EXTCTRL = 0x0010, MII_QPDSTS = 0x0011, MII_10BTOP = 0x0012,
|
||||
MII_EXTCTRL2 = 0x0013
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* MII Control register bit definitions. */
|
||||
enum mii_control_register_bits {
|
||||
MII_CNTL_FDX = 0x0100,
|
||||
MII_CNTL_RST_AUTO = 0x0200,
|
||||
MII_CNTL_ISOLATE = 0x0400,
|
||||
MII_CNTL_PWRDWN = 0x0800,
|
||||
MII_CNTL_AUTO = 0x1000,
|
||||
MII_CNTL_SPEED = 0x2000,
|
||||
MII_CNTL_LPBK = 0x4000,
|
||||
MII_CNTL_RESET = 0x8000
|
||||
};
|
||||
|
||||
/* MII Status register bit */
|
||||
enum mii_status_register_bits {
|
||||
MII_STAT_EXT = 0x0001,
|
||||
MII_STAT_JAB = 0x0002,
|
||||
MII_STAT_LINK = 0x0004,
|
||||
MII_STAT_CAN_AUTO = 0x0008,
|
||||
MII_STAT_FAULT = 0x0010,
|
||||
MII_STAT_AUTO_DONE = 0x0020,
|
||||
MII_STAT_CAN_T = 0x0800,
|
||||
MII_STAT_CAN_T_FDX = 0x1000,
|
||||
MII_STAT_CAN_TX = 0x2000,
|
||||
MII_STAT_CAN_TX_FDX = 0x4000,
|
||||
MII_STAT_CAN_T4 = 0x8000
|
||||
};
|
||||
|
||||
#define MII_ID1_OUI_LO 0xFC00 /* low bits of OUI mask */
|
||||
#define MII_ID1_MODEL 0x03F0 /* model number */
|
||||
#define MII_ID1_REV 0x000F /* model number */
|
||||
|
||||
/* MII NWAY Register Bits ...
|
||||
valid for the ANAR (Auto-Negotiation Advertisement) and
|
||||
ANLPAR (Auto-Negotiation Link Partner) registers */
|
||||
enum mii_nway_register_bits {
|
||||
MII_NWAY_NODE_SEL = 0x001f,
|
||||
MII_NWAY_CSMA_CD = 0x0001,
|
||||
MII_NWAY_T = 0x0020,
|
||||
MII_NWAY_T_FDX = 0x0040,
|
||||
MII_NWAY_TX = 0x0080,
|
||||
MII_NWAY_TX_FDX = 0x0100,
|
||||
MII_NWAY_T4 = 0x0200,
|
||||
MII_NWAY_PAUSE = 0x0400,
|
||||
MII_NWAY_RF = 0x2000,
|
||||
MII_NWAY_ACK = 0x4000,
|
||||
MII_NWAY_NP = 0x8000
|
||||
};
|
||||
|
||||
enum mii_stsout_register_bits {
|
||||
MII_STSOUT_LINK_FAIL = 0x4000,
|
||||
MII_STSOUT_SPD = 0x0080,
|
||||
MII_STSOUT_DPLX = 0x0040
|
||||
};
|
||||
|
||||
enum mii_stsics_register_bits {
|
||||
MII_STSICS_SPD = 0x8000, MII_STSICS_DPLX = 0x4000,
|
||||
MII_STSICS_LINKSTS = 0x0001
|
||||
};
|
||||
|
||||
enum mii_stssum_register_bits {
|
||||
MII_STSSUM_LINK = 0x0008,
|
||||
MII_STSSUM_DPLX = 0x0004,
|
||||
MII_STSSUM_AUTO = 0x0002,
|
||||
MII_STSSUM_SPD = 0x0001
|
||||
};
|
||||
|
||||
enum sis900_revision_id {
|
||||
SIS630A_900_REV = 0x80, SIS630E_900_REV = 0x81,
|
||||
SIS630S_900_REV = 0x82, SIS630EA1_900_REV = 0x83
|
||||
};
|
||||
|
||||
enum sis630_revision_id {
|
||||
SIS630A0 = 0x00, SIS630A1 = 0x01,
|
||||
SIS630B0 = 0x10, SIS630B1 = 0x11
|
||||
};
|
||||
|
||||
#define FDX_CAPABLE_DUPLEX_UNKNOWN 0
|
||||
#define FDX_CAPABLE_HALF_SELECTED 1
|
||||
#define FDX_CAPABLE_FULL_SELECTED 2
|
||||
|
||||
#define HW_SPEED_UNCONFIG 0
|
||||
#define HW_SPEED_HOME 1
|
||||
#define HW_SPEED_10_MBPS 10
|
||||
#define HW_SPEED_100_MBPS 100
|
||||
#define HW_SPEED_DEFAULT (HW_SPEED_100_MBPS)
|
||||
|
||||
#define CRC_SIZE 4
|
||||
#define MAC_HEADER_SIZE 14
|
||||
|
||||
#define TX_BUF_SIZE 1536
|
||||
#define RX_BUF_SIZE 1536
|
||||
|
||||
#define NUM_RX_DESC 4 /* Number of Rx descriptor registers. */
|
||||
|
||||
/* etherboot needs these defined. LinuxBIOS does it for us
|
||||
typedef unsigned char u8;
|
||||
typedef signed char s8;
|
||||
typedef unsigned short u16;
|
||||
typedef signed short s16;
|
||||
typedef unsigned int u32;
|
||||
typedef signed int s32;
|
||||
*/
|
||||
|
||||
/* Time in ticks before concluding the transmitter is hung. */
|
||||
#define TX_TIMEOUT (4*TICKS_PER_SEC)
|
||||
|
||||
typedef struct _BufferDesc {
|
||||
u32 link;
|
||||
volatile u32 cmdsts;
|
||||
u32 bufptr;
|
||||
} BufferDesc;
|
||||
91
src/etherboot/sis900.txt
Normal file
91
src/etherboot/sis900.txt
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
How I added the SIS900 card to Etherboot
|
||||
|
||||
Author: Marty Connor (mdc@thinguin.org)
|
||||
|
||||
Date: 25 Febrary 2001
|
||||
|
||||
Description:
|
||||
|
||||
This file is intended to help people who want to write an Etherboot
|
||||
driver or port another driver to Etherboot. It is a starting point.
|
||||
Perhaps someday I may write a more detailed description of writing an
|
||||
Etherboot driver. This text should help get people started, and
|
||||
studying sis900.[ch] should help show the basic structure and
|
||||
techniques involved in writing and Etherboot driver.
|
||||
|
||||
***********************************************************************
|
||||
|
||||
0. Back up all the files I need to modify:
|
||||
|
||||
cd etherboot-4.7.20/src
|
||||
cp Makefile Makefile.orig
|
||||
cp config.c config.c.orig
|
||||
cp pci.h pci.h.orig
|
||||
cp NIC NIC.orig
|
||||
cp cards.h cards.h.orig
|
||||
|
||||
1. Edit src/Makefile to add SIS900FLAGS to defines
|
||||
|
||||
SIS900FLAGS= -DINCLUDE_SIS900
|
||||
|
||||
2. edit src/pci.h to add PCI signatures for card
|
||||
|
||||
#define PCI_VENDOR_ID_SIS 0x1039
|
||||
#define PCI_DEVICE_ID_SIS900 0x0900
|
||||
#define PCI_DEVICE_ID_SIS7016 0x7016
|
||||
|
||||
3. Edit src/config.c to add the card to the card probe list
|
||||
|
||||
#if defined(INCLUDE_NS8390) || defined(INCLUDE_EEPRO100) ||
|
||||
defined(INCLUDE_LANCE) || defined(INCLUDE_EPIC100) ||
|
||||
defined(INCLUDE_TULIP) || defined(INCLUDE_OTULIP) ||
|
||||
defined(INCLUDE_3C90X) || defined(INCLUDE_3C595) ||
|
||||
defined(INCLUDE_RTL8139) || defined(INCLUDE_VIA_RHINE) ||
|
||||
defined(INCLUDE_SIS900) || defined(INCLUDE_W89C840)
|
||||
|
||||
... and ...
|
||||
|
||||
#ifdef INCLUDE_SIS900
|
||||
{ PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS900,
|
||||
"SIS900", 0, 0, 0, 0},
|
||||
{ PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS7016,
|
||||
"SIS7016", 0, 0, 0, 0},
|
||||
#endif
|
||||
|
||||
... and ...
|
||||
|
||||
#ifdef INCLUDE_SIS900
|
||||
{ "SIS900", sis900_probe, pci_ioaddrs },
|
||||
#endif
|
||||
|
||||
4. Edit NIC to add sis900 and sis7016 to NIC list
|
||||
|
||||
# SIS 900 and SIS 7016
|
||||
sis900 sis900 0x1039,0x0900
|
||||
sis7016 sis900 0x1039,0x7016
|
||||
|
||||
5. Edit cards.h to add sis900 probe routine declaration
|
||||
|
||||
#ifdef INCLUDE_SIS900
|
||||
extern struct nic *sis900_probe(struct nic *, unsigned short *
|
||||
PCI_ARG(struct pci_device *));
|
||||
#endif
|
||||
|
||||
***********************************************************************
|
||||
|
||||
At this point, you can begin creating your driver source file. See
|
||||
the "Writing and Etherboot Driver" section of the Etherboot
|
||||
documentation for some hints. See the skel.c file for a starting
|
||||
point. If there is a Linux driver for the card, you may be able to
|
||||
use that. Copy and learn from existing Etherboot drivers (this is GPL
|
||||
/ Open Source software!).
|
||||
|
||||
Join the etherboot-developers and etherboot-users mailing lists
|
||||
(information is on etherboot.sourceforge.net) for information and
|
||||
assistance. We invite more developers to help improve Etherboot.
|
||||
|
||||
Visit the http://etherboot.sourceforge.net, http://thinguin.org,
|
||||
http://rom-o-matic.net, and http://ltsp.org sites for information and
|
||||
assistance.
|
||||
|
||||
Enjoy.
|
||||
64
src/etherboot/timer.h
Normal file
64
src/etherboot/timer.h
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/* Defines for routines to implement a low-overhead timer for drivers */
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2, or (at
|
||||
* your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef TIMER_H
|
||||
#define TIMER_H
|
||||
|
||||
/* Ports for the 8254 timer chip */
|
||||
#define TIMER2_PORT 0x42
|
||||
#define TIMER_MODE_PORT 0x43
|
||||
|
||||
/* Meaning of the mode bits */
|
||||
#define TIMER0_SEL 0x00
|
||||
#define TIMER1_SEL 0x40
|
||||
#define TIMER2_SEL 0x80
|
||||
#define READBACK_SEL 0xC0
|
||||
|
||||
#define LATCH_COUNT 0x00
|
||||
#define LOBYTE_ACCESS 0x10
|
||||
#define HIBYTE_ACCESS 0x20
|
||||
#define WORD_ACCESS 0x30
|
||||
|
||||
#define MODE0 0x00
|
||||
#define MODE1 0x02
|
||||
#define MODE2 0x04
|
||||
#define MODE3 0x06
|
||||
#define MODE4 0x08
|
||||
#define MODE5 0x0A
|
||||
|
||||
#define BINARY_COUNT 0x00
|
||||
#define BCD_COUNT 0x01
|
||||
|
||||
/* Timers tick over at this rate */
|
||||
#define TICKS_PER_MS 1193
|
||||
|
||||
/* Parallel Peripheral Controller Port B */
|
||||
#define PPC_PORTB 0x61
|
||||
|
||||
/* Meaning of the port bits */
|
||||
#define PPCB_T2OUT 0x20 /* Bit 5 */
|
||||
#define PPCB_SPKR 0x02 /* Bit 1 */
|
||||
#define PPCB_T2GATE 0x01 /* Bit 0 */
|
||||
|
||||
/* Ticks must be between 0 and 65535 (0 == 65536)
|
||||
because it is a 16 bit counter */
|
||||
extern void load_timer2(unsigned int ticks);
|
||||
extern inline int timer2_running(void)
|
||||
{
|
||||
return ((inb(PPC_PORTB) & PPCB_T2OUT) == 0);
|
||||
}
|
||||
|
||||
extern inline void waiton_timer2(unsigned int ticks)
|
||||
{
|
||||
load_timer2(ticks);
|
||||
while ((inb(PPC_PORTB) & PPCB_T2OUT) == 0)
|
||||
;
|
||||
}
|
||||
|
||||
#endif /* TIMER_H */
|
||||
|
|
@ -28,7 +28,11 @@
|
|||
#endif
|
||||
#include "do_inflate.h"
|
||||
|
||||
|
||||
#ifdef USE_TFTP
|
||||
extern void netboot_init(void);
|
||||
extern int tftp_init(const char *name);
|
||||
extern int tftp_fetchone(char *buffer);
|
||||
#endif
|
||||
|
||||
int linuxbiosmain(unsigned long base, unsigned long totalram)
|
||||
{
|
||||
|
|
@ -37,6 +41,11 @@ int linuxbiosmain(unsigned long base, unsigned long totalram)
|
|||
unsigned char *cmd_line;
|
||||
unsigned long initrd_start, initrd_size;
|
||||
|
||||
#ifdef USE_TFTP
|
||||
char buffer[256];
|
||||
char *bufptr;
|
||||
int buflen;
|
||||
#endif
|
||||
|
||||
#if USE_ELF_BOOT
|
||||
return elfboot(totalram);
|
||||
|
|
@ -72,6 +81,16 @@ int linuxbiosmain(unsigned long base, unsigned long totalram)
|
|||
|
||||
post_code(0xf1);
|
||||
|
||||
#ifdef PYRO_TEST1
|
||||
printk(KERN_NOTICE "LiLa loader, press a key to test netboot_init:");
|
||||
buflen = sizeof(buffer);
|
||||
ttys0_rx_line(buffer, &buflen);
|
||||
#endif
|
||||
|
||||
#ifdef USE_TFTP
|
||||
netboot_init();
|
||||
printk(KERN_NOTICE "\nnetboot_init test complete, all is well (I hope!)\n");
|
||||
#endif
|
||||
|
||||
DBG("Gunzip setup\n");
|
||||
gunzip_setup();
|
||||
|
|
@ -83,6 +102,35 @@ int linuxbiosmain(unsigned long base, unsigned long totalram)
|
|||
}
|
||||
post_code(0xf8);
|
||||
|
||||
#ifdef TFTP_INITRD
|
||||
printk("Loading initrd now\n");
|
||||
|
||||
buflen = tftp_init("initrd");
|
||||
printk("TFTP init complete (%d)\n",buflen);
|
||||
buflen = 512; // I know, not it's purpose,
|
||||
// but it isn't being used at this point.
|
||||
bufptr = initrd_start = 0x0400000;
|
||||
while(buflen == 512) {
|
||||
buflen = tftp_fetchone(bufptr);
|
||||
#ifdef DEBUG_TFTP
|
||||
printk("Got block, bufptr = %lu, size= %u\n",bufptr, buflen);
|
||||
#endif
|
||||
bufptr += buflen;
|
||||
}
|
||||
initrd_size = bufptr - initrd_start;
|
||||
|
||||
printk("Initrd loaded\n");
|
||||
|
||||
if(tftp_init("cmdline") >=0) {
|
||||
tftp_fetchone(buffer);
|
||||
cmd_line=buffer;
|
||||
}
|
||||
|
||||
printk("Booting with command line: %s\n",cmd_line);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/* parameter passing to linux. You have to get the pointer to the
|
||||
* empty_zero_page, then fill it in.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -36,6 +36,38 @@ static char rcsid[] = "$Id$";
|
|||
|
||||
#define TTYS0_DIV (115200/TTYS0_BAUD)
|
||||
|
||||
#ifdef PYRO_SERIAL
|
||||
|
||||
/* experimental serial read stuffs */
|
||||
int iskey(void) {
|
||||
if( inb(TTYS0_LSR) & 0x01)
|
||||
return(1);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
char ttys0_rx_char(void) {
|
||||
char result;
|
||||
|
||||
while(!(inb(TTYS0_LSR) & 0x01));
|
||||
|
||||
result = inb(TTYS0_RBR);
|
||||
return(result);
|
||||
}
|
||||
|
||||
void ttys0_rx_line(char *buffer, int *len) {
|
||||
int pos=0;
|
||||
char chargot=0;
|
||||
|
||||
while(chargot != '\r' && chargot != '\n' && pos< *len) {
|
||||
chargot = ttys0_rx_char();
|
||||
buffer[pos++] = chargot;
|
||||
}
|
||||
|
||||
*len = pos-1;
|
||||
}
|
||||
|
||||
#endif
|
||||
void ttys0_init(void)
|
||||
{
|
||||
/* disable interrupts */
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
option SIS630
|
||||
option USE_DOC_MIL
|
||||
# option USE_DOC_MIL
|
||||
option SMA_SIZE=0xA0
|
||||
docipl northsouthbridge/sis/630/ipl.S
|
||||
raminit northsouthbridge/sis/630/raminit.inc
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
option SIS730
|
||||
option USE_DOC_MIL
|
||||
# option USE_DOC_MIL
|
||||
option SMA_SIZE=0xA0
|
||||
docipl northsouthbridge/sis/730/ipl.S
|
||||
raminit northsouthbridge/sis/730/raminit.inc
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@
|
|||
#include "ipl.h"
|
||||
|
||||
.code16
|
||||
#ifdef STD_FLASH
|
||||
.org 0xfe00
|
||||
#endif
|
||||
|
||||
#define SIZE_ALL
|
||||
#define REALLY_COMPACT
|
||||
|
|
@ -210,7 +213,20 @@ sis730ipl_start:
|
|||
movw %ax, %ss
|
||||
movw $SPL_RAM_SEG, %ax
|
||||
movw %ax, %es
|
||||
#ifdef STD_FLASH
|
||||
movw $0xf000, %ax
|
||||
movw %ax, %ds
|
||||
xorw %sp, %sp # clear %sp
|
||||
xorw %si, %si
|
||||
xorw %di, %di
|
||||
movw $0xffff, %cx
|
||||
rep
|
||||
movsb
|
||||
|
||||
movw $DOC_WIN_SEG, %ax
|
||||
movw %ax, %ds
|
||||
|
||||
#else
|
||||
movw $sis950_init_table, %si # unlock SiS 950 LPC
|
||||
movw $0x05, %cx # select Clock Selection
|
||||
movw $0x2e, %dx # and Flash ROM I/F
|
||||
|
|
@ -278,6 +294,7 @@ doc_delay:
|
|||
incw %bp # increse current page number
|
||||
cmpw $128, %bp # moved 63 KB ??
|
||||
jl read_next_page # no, read next page
|
||||
#endif /*else STD_FLASH */
|
||||
|
||||
sis730ipl_end:
|
||||
jmp spl_vector # jump to SPL vector
|
||||
|
|
@ -395,10 +412,18 @@ pci_init_table:
|
|||
|
||||
.word 0x0000 /* Null, End of table */
|
||||
|
||||
.org 0x01f0
|
||||
#ifdef STD_FLASH
|
||||
.org 0xfff0
|
||||
reset_vector:
|
||||
.byte 0xea # jmp to fe00:0000, where IPL
|
||||
.word 0xfe00, 0xf000 # starts in DoC
|
||||
|
||||
#else
|
||||
.org 0x1f0
|
||||
reset_vector:
|
||||
.byte 0xea # jmp to fe00:0000, where IPL
|
||||
.word 0x0000, DOC_WIN_SEG # starts in DoC
|
||||
#endif
|
||||
|
||||
spl_vector:
|
||||
.byte 0xea # jmp to 8000:0000, where SPL
|
||||
|
|
|
|||
|
|
@ -2,3 +2,4 @@ object fill_inbuf.o
|
|||
object rom_fill_inbuf.o
|
||||
object docmil_fill_inbuf.o
|
||||
object tsunami_tigbus_rom_fill_inbuf.o
|
||||
object tftp_fill_inbuf.o
|
||||
|
|
|
|||
|
|
@ -128,6 +128,14 @@ def dir(base_dir, name):
|
|||
def mainboard(dir, mainboard_name):
|
||||
common_command_action(dir, 'mainboard', mainboard_name)
|
||||
|
||||
def etherboot(dir, net_name):
|
||||
common_command_action(dir, 'etherboot', '')
|
||||
option(dir,'OLD_KERNEL_HACK')
|
||||
option(dir,'USE_TFTP')
|
||||
option(dir,'TFTP_INITRD')
|
||||
option(dir,'PYRO_SERIAL')
|
||||
|
||||
|
||||
# old legacy PC junk, which will be dying soon.
|
||||
def keyboard(dir, keyboard_name):
|
||||
if (debug):
|
||||
|
|
@ -363,6 +371,7 @@ command_actions = {
|
|||
'dir' : dir,
|
||||
'keyboard' : keyboard,
|
||||
'docipl' : docipl,
|
||||
'etherboot' : etherboot,
|
||||
'makedefine' : makedefine,
|
||||
'makerule' : makerule,
|
||||
'addaction' : addaction,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue