my solution to lab 6

This commit is contained in:
winPond
2019-07-17 16:08:06 +08:00
parent 8147d99448
commit c62da1c86d
534 changed files with 60875 additions and 6513 deletions

View File

@@ -0,0 +1,88 @@
#include <kern/e1000.h>
#include <kern/pmap.h>
#include <kern/pci.h>
#include <kern/pcireg.h>
#include <inc/string.h>
// LAB 6: Your driver code here
#define E1000_LOCATE(offset) (offset >> 2)
volatile uint32_t *e1000;
/* 为描述符列表分配静态内存 */
struct E1000TxDesc tx_desc_list[TX_DESC_SIZE] __attribute__((aligned (PGSIZE))) ;
char pbuf[TX_DESC_SIZE][TX_PACKET_SIZE] __attribute__((aligned (PGSIZE))) ;
void
e1000_transmit_init()
{
size_t i;
memset(tx_desc_list, 0 , sizeof(struct E1000TxDesc) * TX_DESC_SIZE);
for (i = 0; i < TX_DESC_SIZE; i++) {
tx_desc_list[i].buffer_addr = PADDR(pbuf[i]);
tx_desc_list[i].status = E1000_TXD_STAT_DD;
tx_desc_list[i].cmd = E1000_TXD_CMD_RS | E1000_TXD_CMD_EOP;
}
e1000[E1000_LOCATE(E1000_TDBAL)] = PADDR(tx_desc_list);
e1000[E1000_LOCATE(E1000_TDBAH)] = 0;
e1000[E1000_LOCATE(E1000_TDLEN)] = sizeof(struct E1000TxDesc) * TX_DESC_SIZE;
// ensure that TDH and TDT are 0 index not offset
e1000[E1000_LOCATE(E1000_TDH)] = 0;
e1000[E1000_LOCATE(E1000_TDT)] = 0;
// Initialize the Transmit Control Register (TCTL)
e1000[E1000_LOCATE(E1000_TCTL)] = E1000_TCTL_EN |
E1000_TCTL_PSP |
(E1000_TCTL_CT & (0x10 << 4)) |
(E1000_TCTL_COLD & (0x40 << 12));
// 10 8 6
// 10 8 12
e1000[E1000_LOCATE(E1000_TIPG)] = 10 | (8 << 10) | (12 << 20);
}
int
e1000_transmit(void *addr, size_t len)
{
size_t tdt = e1000[E1000_LOCATE(E1000_TDT)];
struct E1000TxDesc *tail_desc = &tx_desc_list[tdt];
if ( !(tail_desc->status & E1000_TXD_STAT_DD )) {
// Status is not DD
return -1;
}
memmove(pbuf[tdt], addr, len);
tail_desc->length = (uint16_t )len;
// clear DD
tail_desc->status &= (~E1000_TXD_STAT_DD);
e1000[E1000_LOCATE(E1000_TDT)] = (tdt+1) % TX_DESC_SIZE;
return 0;
}
int
pci_e1000_attach(struct pci_func * pcif)
{
int r;
// 使能E1000分配 MMIO等
pci_func_enable(pcif);
// 映射,并保存其虚拟地址,方便访问。
e1000 = mmio_map_region(pcif->reg_base[0], pcif->reg_size[0]);
e1000_transmit_init();
cprintf("device status:[%08x]\n", e1000[E1000_LOCATE(E1000_DEVICE_STATUS)]);
/*
char mes[40] = "e1000 transmit :HELLO";
for (size_t i = 0; i < 10 ; i++) {
e1000_transmit(mes, strlen(mes));
}
*/
return 0;
}

View File

@@ -0,0 +1,86 @@
#ifndef JOS_KERN_E1000_H
#define JOS_KERN_E1000_H
#include <inc/types.h>
#define PCI_E1000_VENDOR_ID 0x8086
#define PCI_E1000_DEVICE_ID 0x100E
/* 循环队列的长度*/
#define TX_DESC_SIZE 32
#define TX_PACKET_SIZE 2048
/* Register Set
*
* RW - register is both readable and writable
*
*/
#define E1000_DEVICE_STATUS 0x00008 /* Device Status - RO */
#define E1000_RCTL 0x00100 /* RX Control - RW */
#define E1000_TCTL 0x00400 /* TX Control - RW */
#define E1000_TDBAL 0x03800 /* TX Descriptor Base Address Low - RW */
#define E1000_TDBAH 0X03804 /* TX Descriptor Base Address High - RW */
#define E1000_TDLEN 0x03808 /* TX Descriptor Length - RW */
#define E1000_TDH 0x03810 /* TX Descriptor Head - RW */
#define E1000_TDT 0x03818 /* TX Descripotr Tail - RW */
#define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */
/* Transmit Control */
#define E1000_TCTL_RST 0x00000001 /* Reserved */
#define E1000_TCTL_EN 0x00000002 /* enable tx */
#define E1000_TCTL_BCE 0x00000004 /* Reserved */
#define E1000_TCTL_PSP 0x00000008 /* pad short packets */
#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */
#define E1000_TCTL_COLD 0x003ff000 /* collision distance */
#define E1000_TCTL_SWXOFF 0x00400000 /* SW Xoff transmission */
#define E1000_TCTL_PBE 0x00800000 /* Reserved */
#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */
#define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */
#define E1000_TCTL_MULR 0x10000000 /* Reserved */
/* Transmit Descriptor */
struct E1000TxDesc {
uint64_t buffer_addr; /* Address of the descriptor's data buffer */
uint16_t length; /* Data buffer length */
uint8_t cso; /* Checksum offset */
uint8_t cmd; /* Descriptor control */
uint8_t status; /* Descriptor status */
uint8_t css; /* Checksum start */
uint16_t special;
}__attribute__((packed));
/* Transmit Descriptor bit definitions */
#define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */
#define E1000_TXD_DTYP_C 0x00000000 /* Context Descriptor */
#define E1000_TXD_CMD_EOP 0x01 /* End of Packet */
#define E1000_TXD_CMD_RS 0x08 /* Report Status */
#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */
#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */
#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */
#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */
#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */
int e1000_transmit(void *addr, size_t len);
#endif // SOL >= 6

View File

@@ -0,0 +1,88 @@
#include <kern/e1000.h>
#include <kern/pmap.h>
#include <kern/pci.h>
#include <kern/pcireg.h>
#include <inc/string.h>
// LAB 6: Your driver code here
#define E1000_LOCATE(offset) (offset >> 2)
volatile uint32_t *e1000;
/* 为描述符列表分配静态内存 */
struct E1000TxDesc tx_desc_list[TX_DESC_SIZE] __attribute__((aligned (PGSIZE))) ;
char pbuf[TX_DESC_SIZE][TX_PACKET_SIZE] __attribute__((aligned (PGSIZE))) ;
void
e1000_transmit_init()
{
size_t i;
memset(tx_desc_list, 0 , sizeof(struct E1000TxDesc) * TX_DESC_SIZE);
for (i = 0; i < TX_DESC_SIZE; i++) {
tx_desc_list[i].buffer_addr = PADDR(pbuf[i]);
tx_desc_list[i].status = E1000_TXD_STAT_DD;
tx_desc_list[i].cmd = E1000_TXD_CMD_RS | E1000_TXD_CMD_EOP;
}
e1000[E1000_LOCATE(E1000_TDBAL)] = PADDR(tx_desc_list);
e1000[E1000_LOCATE(E1000_TDBAH)] = 0;
e1000[E1000_LOCATE(E1000_TDLEN)] = sizeof(struct E1000TxDesc) * TX_DESC_SIZE;
// ensure that TDH and TDT are 0 index not offset
e1000[E1000_LOCATE(E1000_TDH)] = 0;
e1000[E1000_LOCATE(E1000_TDT)] = 0;
// Initialize the Transmit Control Register (TCTL)
e1000[E1000_LOCATE(E1000_TCTL)] = E1000_TCTL_EN |
E1000_TCTL_PSP |
(E1000_TCTL_CT & (0x10 << 4)) |
(E1000_TCTL_COLD & (0x40 << 12));
// 10 8 6
// 10 8 12
e1000[E1000_LOCATE(E1000_TIPG)] = 10 | (8 << 10) | (12 << 20);
}
int
e1000_transmit(void *addr, size_t len)
{
size_t tdt = e1000[E1000_LOCATE(E1000_TDT)];
struct E1000TxDesc *tail_desc = &tx_desc_list[tdt];
if ( !(tail_desc->status & E1000_TXD_STAT_DD )) {
// Status is not DD
return -1;
}
memmove(pbuf[tdt], addr, len);
tail_desc->length = (uint16_t )len;
// clear DD
tail_desc->status &= (~E1000_TXD_STAT_DD);
e1000[E1000_LOCATE(E1000_TDT)] = (tdt+1) % TX_DESC_SIZE;
return 0;
}
int
pci_e1000_attach(struct pci_func * pcif)
{
int r;
// 使能E1000分配 MMIO等
pci_func_enable(pcif);
// 映射,并保存其虚拟地址,方便访问。
e1000 = mmio_map_region(pcif->reg_base[0], pcif->reg_size[0]);
e1000_transmit_init();
cprintf("device status:[%08x]\n", e1000[E1000_LOCATE(E1000_DEVICE_STATUS)]);
/*
char mes[40] = "e1000 transmit :HELLO";
for (size_t i = 0; i < 10 ; i++) {
e1000_transmit(mes, strlen(mes));
}
*/
return 0;
}

View File

@@ -0,0 +1,59 @@
#include <kern/e1000.h>
#include <kern/pmap.h>
#include <kern/pci.h>
#include <kern/pcireg.h>
#include <inc/string.h>
// LAB 6: Your driver code here
#define E1000_LOCATE(offset) (offset >> 2)
volatile uint32_t *e1000;
/* 为描述符列表分配静态内存 */
struct E1000TxDesc tx_desc_list[TX_DESC_SIZE];
struct Packet pack_buf[TX_DESC_SIZE];
void
e1000_transmit_init()
{
size_t i;
memset(tx_desc_list, 0 , sizeof(struct E1000TxDesc) * TX_DESC_SIZE);
for (i = 0; i < TX_DESC_SIZE; i++) {
tx_desc_list[i].buffer_addr = PADDR(&pack_buf[i]);
tx_desc_list[i].status |= E1000_TXD_STAT_DD;
tx_desc_list[i].cmd |= E1000_TXD_CMD_RS;
}
e1000[E1000_LOCATE(E1000_TDBAL)] = PADDR(tx_desc_list);
e1000[E1000_LOCATE(E1000_TDBAH)] = 0;
e1000[E1000_LOCATE(E1000_TDLEN)] = sizeof(struct E1000TxDesc) * TX_DESC_SIZE;
// ensure that TDH and TDT are 0
e1000[E1000_LOCATE(E1000_TDH)] = 0;
e1000[E1000_LOCATE(E1000_TDT)] = 0;
// Initialize the Transmit Control Register (TCTL)
e1000[E1000_LOCATE(E1000_TCTL)] |= E1000_TCTL_EN;
e1000[E1000_LOCATE(E1000_TCTL)] |= E1000_TCTL_PSP;
e1000[E1000_LOCATE(E1000_TCTL)] |= (E1000_TCTL_CT & (0x10 << 4));
e1000[E1000_LOCATE(E1000_TCTL)] |= (E1000_TCTL_CT & (0x40 << 12));
e1000[E1000_LOCATE(E1000_TIPG)] = 10 | (8 << 10) | (6 << 20);
}
int
pci_e1000_attach(struct pci_func * pcif)
{
int r;
// 使能E1000分配 MMIO等
pci_func_enable(pcif);
// 映射,并保存其虚拟地址,方便访问。
e1000 = mmio_map_region(pcif->reg_base[0], pcif->reg_size[0]);
e1000_transmit_init();
cprintf("device status:[%08x]\n", e1000[E1000_LOCATE(E1000_DEVICE_STATUS)]);
return 0;
}

View File

@@ -0,0 +1,86 @@
#ifndef JOS_KERN_E1000_H
#define JOS_KERN_E1000_H
#include <inc/types.h>
#define PCI_E1000_VENDOR_ID 0x8086
#define PCI_E1000_DEVICE_ID 0x100E
/* 循环队列的长度*/
#define TX_DESC_SIZE 32
#define TX_PACKET_SIZE 2048
/* Register Set
*
* RW - register is both readable and writable
*
*/
#define E1000_DEVICE_STATUS 0x00008 /* Device Status - RO */
#define E1000_RCTL 0x00100 /* RX Control - RW */
#define E1000_TCTL 0x00400 /* TX Control - RW */
#define E1000_TDBAL 0x03800 /* TX Descriptor Base Address Low - RW */
#define E1000_TDBAH 0X03804 /* TX Descriptor Base Address High - RW */
#define E1000_TDLEN 0x03808 /* TX Descriptor Length - RW */
#define E1000_TDH 0x03810 /* TX Descriptor Head - RW */
#define E1000_TDT 0x03818 /* TX Descripotr Tail - RW */
#define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */
/* Transmit Control */
#define E1000_TCTL_RST 0x00000001 /* Reserved */
#define E1000_TCTL_EN 0x00000002 /* enable tx */
#define E1000_TCTL_BCE 0x00000004 /* Reserved */
#define E1000_TCTL_PSP 0x00000008 /* pad short packets */
#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */
#define E1000_TCTL_COLD 0x003ff000 /* collision distance */
#define E1000_TCTL_SWXOFF 0x00400000 /* SW Xoff transmission */
#define E1000_TCTL_PBE 0x00800000 /* Reserved */
#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */
#define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */
#define E1000_TCTL_MULR 0x10000000 /* Reserved */
/* Transmit Descriptor */
struct E1000TxDesc {
uint64_t buffer_addr; /* Address of the descriptor's data buffer */
uint16_t length; /* Data buffer length */
uint8_t cso; /* Checksum offset */
uint8_t cmd; /* Descriptor control */
uint8_t status; /* Descriptor status */
uint8_t css; /* Checksum start */
uint16_t special;
}__attribute__((packed));
/* Transmit Descriptor bit definitions */
#define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */
#define E1000_TXD_DTYP_C 0x00000000 /* Context Descriptor */
#define E1000_TXD_CMD_EOP 0x01 /* End of Packet */
#define E1000_TXD_CMD_RS 0x08 /* Report Status */
#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */
#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */
#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */
#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */
#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */
int e1000_transmit(void *addr, size_t len);
#endif // SOL >= 6

View File

@@ -0,0 +1,131 @@
#ifndef JOS_KERN_E1000_H
#define JOS_KERN_E1000_H
#include "kern/pci.h"
#define E1000_VENDER_ID_82540EM 0x8086
#define E1000_DEV_ID_82540EM 0x100E
#define TXDESCS 32
#define TX_PKT_SIZE 1518
#define E1000_STATUS 0x00008 /* Device Status - RO */
#define E1000_TCTL 0x00400 /* TX Control - RW */
#define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */
#define E1000_TDBAL 0x03800 /* TX Descriptor Base Address Low - RW */
#define E1000_TDBAH 0x03804 /* TX Descriptor Base Address High - RW */
#define E1000_TDLEN 0x03808 /* TX Descriptor Length - RW */
#define E1000_TDH 0x03810 /* TX Descriptor Head - RW */
#define E1000_TDT 0x03818 /* TX Descripotr Tail - RW */
#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */
#define E1000_TXD_CMD_EOP 0x00000001 /* End of Packet */
#define E1000_TXD_CMD_RS 0x00000008 /* Report Status */
#define RXDESCS 128
#define RX_PKT_SIZE 1518
#define E1000_RCTL 0x00100
#define E1000_RCTL_EN 0x00000002 /* enable */
#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */
#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */
#define E1000_RDBAL 0x02800 /* RX Descriptor Base Address Low - RW */
#define E1000_RDBAH 0x02804 /* RX Descriptor Base Address High - RW */
#define E1000_RDLEN 0x02808 /* RX Descriptor Length - RW */
#define E1000_RDH 0x02810 /* RX Descriptor Head - RW */
#define E1000_RDT 0x02818 /* RX Descriptor Tail - RW */
#define E1000_RA 0x05400 /* Receive Address - RW Array */
#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */
#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */
#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */
enum {
E_TRANSMIT_RETRY = 1,
E_RECEIVE_RETRY,
};
/*transmit descriptor related*/
struct e1000_tx_desc
{
uint64_t addr;
uint16_t length;
uint8_t cso;
uint8_t cmd;
uint8_t status;
uint8_t css;
uint16_t special;
}__attribute__((packed));
struct e1000_tctl {
uint32_t rsv1: 1;
uint32_t en: 1;
uint32_t rsv2: 1;
uint32_t psp: 1;
uint32_t ct: 8;
uint32_t cold: 10;
uint32_t swxoff: 1;
uint32_t rsv3: 1;
uint32_t rtlc: 1;
uint32_t nrtu: 1;
uint32_t rsv4: 6;
};
struct e1000_tipg {
uint32_t ipgt: 10;
uint32_t ipgr1: 10;
uint32_t ipgr2: 10;
uint32_t rsv: 2;
};
struct e1000_tdt {
uint16_t tdt;
uint16_t rsv;
};
struct e1000_tdlen {
uint32_t zero: 7;
uint32_t len: 13;
uint32_t rsv: 12;
};
struct e1000_tdh {
uint16_t tdh;
uint16_t rsv;
};
/*receive descriptor related*/
struct e1000_rx_desc {
uint64_t addr;
uint16_t length;
uint16_t chksum;
uint8_t status;
uint8_t errors;
uint16_t special;
}__attribute__((packed));
struct e1000_rdlen {
unsigned zero: 7;
unsigned len: 13;
unsigned rsv: 12;
};
struct e1000_rdh {
uint16_t rdh;
uint16_t rsv;
};
struct e1000_rdt {
uint16_t rdt;
uint16_t rsv;
};
int e1000_attachfn(struct pci_func *pcif);
static void e1000_transmit_init();
int e1000_transmit(void *data, size_t len);
static void e1000_receive_init();
int e1000_receive(void *addr, size_t *len);
#endif // JOS_KERN_E1000_H

View File

@@ -0,0 +1,94 @@
#ifndef JOS_KERN_E1000_H
#define JOS_KERN_E1000_H
#include <inc/types.h>
#define PCI_E1000_VENDOR_ID 0x8086
#define PCI_E1000_DEVICE_ID 0x100E
/* 循环队列的长度*/
#define TX_DESC_SIZE 32
/* Register Set
*
* RW - register is both readable and writable
*
*/
#define E1000_DEVICE_STATUS 0x00008 /* Device Status - RO */
#define E1000_RCTL 0x00100 /* RX Control - RW */
#define E1000_TCTL 0x00400 /* TX Control - RW */
#define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */
#define E1000_TDBAL 0x03800 /* TX Descriptor Base Address Low - RW */
#define E1000_TDBAH 0X03804 /* TX Descriptor Base Address High - RW */
#define E1000_TDLEN 0x03808 /* TX Descriptor Length - RW */
#define E1000_TDH 0x03810 /* TX Descriptor Head - RW */
#define E1000_TDT 0x03818 /* TX Descripotr Tail - RW */
/* Transmit Control */
#define E1000_TCTL_RST 0x00000001 /* Reserved */
#define E1000_TCTL_EN 0x00000002 /* enable tx */
#define E1000_TCTL_BCE 0x00000004 /* Reserved */
#define E1000_TCTL_PSP 0x00000008 /* pad short packets */
#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */
#define E1000_TCTL_COLD 0x003ff000 /* collision distance */
#define E1000_TCTL_SWXOFF 0x00400000 /* SW Xoff transmission */
#define E1000_TCTL_PBE 0x00800000 /* Reserved */
#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */
#define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */
#define E1000_TCTL_MULR 0x10000000 /* Reserved */
/* Transmit Descriptor */
struct E1000TxDesc {
uint64_t buffer_addr; /* Address of the descriptor's data buffer */
uint16_t length; /* Data buffer length */
uint8_t cso; /* Checksum offset */
uint8_t cmd; /* Descriptor control */
uint8_t status; /* Descriptor status */
uint8_t css; /* Checksum start */
uint16_t special;
}__attribute__((packed));
/* Transmit Descriptor bit definitions */
#define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */
#define E1000_TXD_DTYP_C 0x00000000 /* Context Descriptor */
#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */
#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */
#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */
#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */
#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */
#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */
#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */
#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */
#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */
#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */
#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */
#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */
#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */
#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */
#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */
#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */
#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */
#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */
/* packet buffer*/
struct Packet {
char body[2048];
};
#endif // SOL >= 6

View File

@@ -0,0 +1,148 @@
#include <kern/e1000.h>
#include <kern/pmap.h>
#include <kern/pci.h>
#include <kern/pcireg.h>
#include <inc/string.h>
// LAB 6: Your driver code here
#define E1000_LOCATE(offset) (offset >> 2)
volatile uint32_t *e1000;
uint32_t E1000_MAC[6] = {0x52, 0x54, 0x00, 0x12, 0x34, 0x56};
/* 为描述符列表分配静态内存 */
struct E1000TxDesc tx_desc_list[TX_DESC_SIZE] __attribute__((aligned (PGSIZE))) ;
char tx_pbuf[TX_DESC_SIZE][TX_PACKET_SIZE] __attribute__((aligned (PGSIZE))) ;
struct E1000RxDesc rx_desc_list[RX_DESC_SIZE] __attribute__((aligned (PGSIZE))) ;
char rx_pbuf[RX_DESC_SIZE][RX_PACKET_SIZE] __attribute__((aligned (PGSIZE))) ;
void
e1000_transmit_init()
{
size_t i;
memset(tx_desc_list, 0 , sizeof(struct E1000TxDesc) * TX_DESC_SIZE);
for (i = 0; i < TX_DESC_SIZE; i++) {
tx_desc_list[i].buffer_addr = PADDR(tx_pbuf[i]);
tx_desc_list[i].status = E1000_TXD_STAT_DD;
tx_desc_list[i].cmd = E1000_TXD_CMD_RS | E1000_TXD_CMD_EOP;
}
e1000[E1000_LOCATE(E1000_TDBAL)] = PADDR(tx_desc_list);
e1000[E1000_LOCATE(E1000_TDBAH)] = 0;
e1000[E1000_LOCATE(E1000_TDLEN)] = sizeof(struct E1000TxDesc) * TX_DESC_SIZE;
// ensure that TDH and TDT are 0 index not offset
e1000[E1000_LOCATE(E1000_TDH)] = 0;
e1000[E1000_LOCATE(E1000_TDT)] = 0;
// Initialize the Transmit Control Register (TCTL)
e1000[E1000_LOCATE(E1000_TCTL)] = E1000_TCTL_EN |
E1000_TCTL_PSP |
(E1000_TCTL_CT & (0x10 << 4)) |
(E1000_TCTL_COLD & (0x40 << 12));
// 10 8 6
// 10 8 12
e1000[E1000_LOCATE(E1000_TIPG)] = 10 | (8 << 10) | (12 << 20);
}
int
e1000_transmit(void *addr, size_t len)
{
size_t tdt = e1000[E1000_LOCATE(E1000_TDT)];
struct E1000TxDesc *tail_desc = &tx_desc_list[tdt];
if ( !(tail_desc->status & E1000_TXD_STAT_DD )) {
// Status is not DD
return -1;
}
memmove(tx_pbuf[tdt], addr, len);
tail_desc->length = (uint16_t )len;
// clear DD
tail_desc->status &= (~E1000_TXD_STAT_DD);
e1000[E1000_LOCATE(E1000_TDT)] = (tdt+1) % TX_DESC_SIZE;
// cprintf("transmit a packet: %s", addr);
return 0;
}
void
e1000_set_mac_addr(uint32_t mac[])
{
uint32_t low = 0, high = 0;
int i;
for (i = 0; i < 4; i++) {
low |= mac[i] << (8 * i);
}
for (i = 4; i < 6; i++) {
high |= mac[i] << (8 * i);
}
e1000[E1000_LOCATE(E1000_RA)] = low;
e1000[E1000_LOCATE(E1000_RA) + 1] = high | E1000_RAH_AV;
}
void
e1000_receive_init()
{
size_t i;
memset(rx_desc_list, 0 , sizeof(struct E1000RxDesc) * RX_DESC_SIZE);
for (i = 0; i < RX_DESC_SIZE; i++) {
rx_desc_list[i].buffer_addr = PADDR(rx_pbuf[i]);
}
e1000_set_mac_addr(E1000_MAC);
cprintf("mac addr %x:%x", e1000[E1000_LOCATE(E1000_RA)], e1000[E1000_LOCATE(E1000_RA) + 1] );
e1000[E1000_LOCATE(E1000_ICS)] = 0;
e1000[E1000_LOCATE(E1000_IMS)] = 0;
e1000[E1000_LOCATE(E1000_RDBAL)] = PADDR(rx_desc_list);
e1000[E1000_LOCATE(E1000_RDBAH)] = 0;
e1000[E1000_LOCATE(E1000_RDLEN)] = sizeof(struct E1000RxDesc) * RX_DESC_SIZE;
e1000[E1000_LOCATE(E1000_RDH)] = RX_DESC_SIZE - 1;
e1000[E1000_LOCATE(E1000_RDH)] = 0;
e1000[E1000_LOCATE(E1000_RCTL)] = E1000_RCTL_EN | E1000_RCTL_SECRC | E1000_RCTL_BAM | E1000_RCTL_SZ_2048;
}
int e1000_receive(void *buf, size_t *len)
{
static size_t next = 0;
size_t tail = e1000[E1000_LOCATE(E1000_RDT)];
if ( !(rx_desc_list[next].status & E1000_RXD_STAT_DD) ) {
// cprintf("no packet\n");
return -1;
}
*len = rx_desc_list[next].length;
memcpy(buf, rx_pbuf[next], *len);
rx_desc_list[next].status &= ~E1000_RXD_STAT_DD;
next = (next + 1) % RX_DESC_SIZE;
e1000[E1000_LOCATE(E1000_RDT)] = (tail + 1 ) % RX_DESC_SIZE;
cprintf("e1000_receive return 0\n");
return 0;
}
int
pci_e1000_attach(struct pci_func * pcif)
{
int r;
// 使能E1000分配 MMIO等
pci_func_enable(pcif);
// 映射,并保存其虚拟地址,方便访问。
e1000 = mmio_map_region(pcif->reg_base[0], pcif->reg_size[0]);
e1000_transmit_init();
e1000_receive_init();
cprintf("device status:[%08x]\n", e1000[E1000_LOCATE(E1000_DEVICE_STATUS)]);
return 0;
}

View File

@@ -0,0 +1,120 @@
#ifndef JOS_KERN_E1000_H
#define JOS_KERN_E1000_H
#include <inc/types.h>
#define PCI_E1000_VENDOR_ID 0x8086
#define PCI_E1000_DEVICE_ID 0x100E
/* 循环队列的长度*/
#define TX_DESC_SIZE 32
#define TX_PACKET_SIZE 2048
#define RX_DESC_SIZE 128
#define RX_PACKET_SIZE 2048
/* Register Set
*
* RW - register is both readable and writable
*
*/
#define E1000_DEVICE_STATUS 0x00008 /* Device Status - RO */
#define E1000_RCTL 0x00100 /* RX Control - RW */
#define E1000_TCTL 0x00400 /* TX Control - RW */
#define E1000_RDBAL 0x02800 /* RX Descriptor Base Address Low - RW */
#define E1000_RDBAH 0x02804 /* RX Descriptor Base Address High - RW */
#define E1000_RDLEN 0x02808 /* RX Descriptor Length - RW */
#define E1000_RDH 0x02810 /* RX Descriptor Head - RW */
#define E1000_RDT 0x02818 /* RX Descriptor Tail - RW */
#define E1000_RA 0x05400 /* Receive Address - RW Array */
#define E1000_TDBAL 0x03800 /* TX Descriptor Base Address Low - RW */
#define E1000_TDBAH 0X03804 /* TX Descriptor Base Address High - RW */
#define E1000_TDLEN 0x03808 /* TX Descriptor Length - RW */
#define E1000_TDH 0x03810 /* TX Descriptor Head - RW */
#define E1000_TDT 0x03818 /* TX Descripotr Tail - RW */
#define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */
/* Transmit Control */
#define E1000_TCTL_RST 0x00000001 /* Reserved */
#define E1000_TCTL_EN 0x00000002 /* enable tx */
#define E1000_TCTL_BCE 0x00000004 /* Reserved */
#define E1000_TCTL_PSP 0x00000008 /* pad short packets */
#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */
#define E1000_TCTL_COLD 0x003ff000 /* collision distance */
#define E1000_TCTL_SWXOFF 0x00400000 /* SW Xoff transmission */
#define E1000_TCTL_PBE 0x00800000 /* Reserved */
#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */
#define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */
#define E1000_TCTL_MULR 0x10000000 /* Reserved */
#define E1000_RCTL_EN 0x00000002 /* enable */
#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */
#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */
/* Transmit Descriptor */
struct E1000TxDesc {
uint64_t buffer_addr; /* Address of the descriptor's data buffer */
uint16_t length; /* Data buffer length */
uint8_t cso; /* Checksum offset */
uint8_t cmd; /* Descriptor control */
uint8_t status; /* Descriptor status */
uint8_t css; /* Checksum start */
uint16_t special;
}__attribute__((packed));
/* Transmit Descriptor bit definitions */
#define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */
#define E1000_TXD_DTYP_C 0x00000000 /* Context Descriptor */
#define E1000_TXD_CMD_EOP 0x01 /* End of Packet */
#define E1000_TXD_CMD_RS 0x08 /* Report Status */
#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */
#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */
#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */
#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */
#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */
/* Receive Descriptor */
struct E1000RxDesc {
uint64_t buffer_addr;
uint16_t length; /* Data buffer length */
uint16_t chksum; /* Check Sum */
uint8_t status;
uint8_t err;
uint16_t special;
};
/* Transmit Descriptor bit definitions */
#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */
#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */
#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */
int e1000_transmit(void *addr, size_t len);
#endif // SOL >= 6

View File

@@ -0,0 +1,131 @@
#ifndef JOS_KERN_E1000_H
#define JOS_KERN_E1000_H
#include "kern/pci.h"
#define E1000_VENDER_ID_82540EM 0x8086
#define E1000_DEV_ID_82540EM 0x100E
#define TXDESCS 32
#define TX_PKT_SIZE 1518
#define E1000_STATUS 0x00008 /* Device Status - RO */
#define E1000_TCTL 0x00400 /* TX Control - RW */
#define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */
#define E1000_TDBAL 0x03800 /* TX Descriptor Base Address Low - RW */
#define E1000_TDBAH 0x03804 /* TX Descriptor Base Address High - RW */
#define E1000_TDLEN 0x03808 /* TX Descriptor Length - RW */
#define E1000_TDH 0x03810 /* TX Descriptor Head - RW */
#define E1000_TDT 0x03818 /* TX Descripotr Tail - RW */
#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */
#define E1000_TXD_CMD_EOP 0x00000001 /* End of Packet */
#define E1000_TXD_CMD_RS 0x00000008 /* Report Status */
#define RXDESCS 128
#define RX_PKT_SIZE 1518
#define E1000_RCTL 0x00100
#define E1000_RCTL_EN 0x00000002 /* enable */
#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */
#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */
#define E1000_RDBAL 0x02800 /* RX Descriptor Base Address Low - RW */
#define E1000_RDBAH 0x02804 /* RX Descriptor Base Address High - RW */
#define E1000_RDLEN 0x02808 /* RX Descriptor Length - RW */
#define E1000_RDH 0x02810 /* RX Descriptor Head - RW */
#define E1000_RDT 0x02818 /* RX Descriptor Tail - RW */
#define E1000_RA 0x05400 /* Receive Address - RW Array */
#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */
#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */
#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */
enum {
E_TRANSMIT_RETRY = 1,
E_RECEIVE_RETRY,
};
/*transmit descriptor related*/
struct e1000_tx_desc
{
uint64_t addr;
uint16_t length;
uint8_t cso;
uint8_t cmd;
uint8_t status;
uint8_t css;
uint16_t special;
}__attribute__((packed));
struct e1000_tctl {
uint32_t rsv1: 1;
uint32_t en: 1;
uint32_t rsv2: 1;
uint32_t psp: 1;
uint32_t ct: 8;
uint32_t cold: 10;
uint32_t swxoff: 1;
uint32_t rsv3: 1;
uint32_t rtlc: 1;
uint32_t nrtu: 1;
uint32_t rsv4: 6;
};
struct e1000_tipg {
uint32_t ipgt: 10;
uint32_t ipgr1: 10;
uint32_t ipgr2: 10;
uint32_t rsv: 2;
};
struct e1000_tdt {
uint16_t tdt;
uint16_t rsv;
};
struct e1000_tdlen {
uint32_t zero: 7;
uint32_t len: 13;
uint32_t rsv: 12;
};
struct e1000_tdh {
uint16_t tdh;
uint16_t rsv;
};
/*receive descriptor related*/
struct e1000_rx_desc {
uint64_t addr;
uint16_t length;
uint16_t chksum;
uint8_t status;
uint8_t errors;
uint16_t special;
}__attribute__((packed));
struct e1000_rdlen {
unsigned zero: 7;
unsigned len: 13;
unsigned rsv: 12;
};
struct e1000_rdh {
uint16_t rdh;
uint16_t rsv;
};
struct e1000_rdt {
uint16_t rdt;
uint16_t rsv;
};
int e1000_attachfn(struct pci_func *pcif);
static void e1000_transmit_init();
int e1000_transmit(void *data, size_t len);
static void e1000_receive_init();
int e1000_receive(void *addr, size_t *len);
#endif // JOS_KERN_E1000_H

View File

@@ -0,0 +1,126 @@
#include <kern/e1000.h>
#include <kern/pmap.h>
#include <kern/pci.h>
#include <kern/pcireg.h>
#include <inc/string.h>
// LAB 6: Your driver code here
#define E1000_LOCATE(offset) (offset >> 2)
volatile uint32_t *e1000;
uint32_t E1000_MAC[6] = {0x52, 0x54, 0x00, 0x12, 0x34, 0x56};
/* 为描述符列表分配静态内存 */
struct E1000TxDesc tx_desc_list[TX_DESC_SIZE] __attribute__((aligned (PGSIZE))) ;
char tx_pbuf[TX_DESC_SIZE][TX_PACKET_SIZE] __attribute__((aligned (PGSIZE))) ;
struct E1000RxDesc rx_desc_list[RX_DESC_SIZE] __attribute__((aligned (PGSIZE))) ;
char rx_pbuf[RX_DESC_SIZE][RX_PACKET_SIZE] __attribute__((aligned (PGSIZE))) ;
void
e1000_transmit_init()
{
size_t i;
memset(tx_desc_list, 0 , sizeof(struct E1000TxDesc) * TX_DESC_SIZE);
for (i = 0; i < TX_DESC_SIZE; i++) {
tx_desc_list[i].buffer_addr = PADDR(tx_pbuf[i]);
tx_desc_list[i].status = E1000_TXD_STAT_DD;
tx_desc_list[i].cmd = E1000_TXD_CMD_RS | E1000_TXD_CMD_EOP;
}
e1000[E1000_LOCATE(E1000_TDBAL)] = PADDR(tx_desc_list);
e1000[E1000_LOCATE(E1000_TDBAH)] = 0;
e1000[E1000_LOCATE(E1000_TDLEN)] = sizeof(struct E1000TxDesc) * TX_DESC_SIZE;
// ensure that TDH and TDT are 0 index not offset
e1000[E1000_LOCATE(E1000_TDH)] = 0;
e1000[E1000_LOCATE(E1000_TDT)] = 0;
// Initialize the Transmit Control Register (TCTL)
e1000[E1000_LOCATE(E1000_TCTL)] = E1000_TCTL_EN |
E1000_TCTL_PSP |
(E1000_TCTL_CT & (0x10 << 4)) |
(E1000_TCTL_COLD & (0x40 << 12));
// 10 8 6
// 10 8 12
e1000[E1000_LOCATE(E1000_TIPG)] = 10 | (8 << 10) | (12 << 20);
}
int
e1000_transmit(void *addr, size_t len)
{
size_t tdt = e1000[E1000_LOCATE(E1000_TDT)];
struct E1000TxDesc *tail_desc = &tx_desc_list[tdt];
if ( !(tail_desc->status & E1000_TXD_STAT_DD )) {
// Status is not DD
return -1;
}
memmove(tx_pbuf[tdt], addr, len);
tail_desc->length = (uint16_t )len;
// clear DD
tail_desc->status &= (~E1000_TXD_STAT_DD);
e1000[E1000_LOCATE(E1000_TDT)] = (tdt+1) % TX_DESC_SIZE;
return 0;
}
void e1000_set_mac_addr(uint32_t mac[])
{
uint32_t low = 0, high = 0;
int i;
for (i = 0; i < 4; i++) {
low |= mac[i] << (8 * i);
}
for (i = 4; i < 6; i++) {
high |= mac[i] << (8 * i);
}
e1000[E1000_LOCATE(E1000_RA)] = low;
e1000[E1000_LOCATE(E1000_RA) + 1] = high | E1000_RAH_AV;
}
void e1000_receive_init()
{
size_t i;
memset(rx_desc_list, 0 , sizeof(struct E1000RxDesc) * RX_DESC_SIZE);
for (i = 0; i < RX_DESC_SIZE; i++) {
rx_desc_list[i].buffer_addr = PADDR(rx_pbuf[i]);
}
e1000[E1000_LOCATE(E1000_RDBAL)] = PADDR(rx_desc_list);
e1000[E1000_LOCATE(E1000_RDBAH)] = 0;
e1000[E1000_LOCATE(E1000_RDLEN)] = sizeof(struct E1000RxDesc) * RX_DESC_SIZE;
}
int
pci_e1000_attach(struct pci_func * pcif)
{
int r;
// 使能E1000分配 MMIO等
pci_func_enable(pcif);
// 映射,并保存其虚拟地址,方便访问。
e1000 = mmio_map_region(pcif->reg_base[0], pcif->reg_size[0]);
e1000_transmit_init();
cprintf("device status:[%08x]\n", e1000[E1000_LOCATE(E1000_DEVICE_STATUS)]);
/*
char mes[40] = "e1000 transmit :HELLO";
for (size_t i = 0; i < 10 ; i++) {
e1000_transmit(mes, strlen(mes));
}
*/
return 0;
}

View File

@@ -0,0 +1,162 @@
#include <kern/e1000.h>
#include <kern/pmap.h>
#include <inc/string.h>
// LAB 6: Your driver code here
volatile void *bar_va;
#define E1000REG(offset) (void *)(bar_va + offset)
struct e1000_tdh *tdh;
struct e1000_tdt *tdt;
struct e1000_tx_desc tx_desc_array[TXDESCS];
char tx_buffer_array[TXDESCS][TX_PKT_SIZE];
struct e1000_rdh *rdh;
struct e1000_rdt *rdt;
struct e1000_rx_desc rx_desc_array[RXDESCS];
char rx_buffer_array[RXDESCS][RX_PKT_SIZE];
uint32_t E1000_MAC[6] = {0x52, 0x54, 0x00, 0x12, 0x34, 0x56};
int
e1000_attachfn(struct pci_func *pcif)
{
pci_func_enable(pcif);
cprintf("reg_base:%x, reg_size:%x\n", pcif->reg_base[0], pcif->reg_size[0]);
bar_va = mmio_map_region(pcif->reg_base[0], pcif->reg_size[0]);
uint32_t *status_reg = (uint32_t *)E1000REG(E1000_STATUS);
assert(*status_reg == 0x80080783);
e1000_transmit_init();
e1000_receive_init();
/*
* transmit test
*/
// char *data = "transmit test";
// e1000_transmit(data, 13);
return 0;
}
static void
e1000_transmit_init()
{
int i;
for (i = 0; i < TXDESCS; i++) {
tx_desc_array[i].addr = PADDR(tx_buffer_array[i]);
tx_desc_array[i].cmd = 0;
tx_desc_array[i].status |= E1000_TXD_STAT_DD;
}
struct e1000_tdlen *tdlen = (struct e1000_tdlen *)E1000REG(E1000_TDLEN);
tdlen->len = TXDESCS;
uint32_t *tdbal = (uint32_t *)E1000REG(E1000_TDBAL);
*tdbal = PADDR(tx_desc_array);
uint32_t *tdbah = (uint32_t *)E1000REG(E1000_TDBAH);
*tdbah = 0;
tdh = (struct e1000_tdh *)E1000REG(E1000_TDH);
tdh->tdh = 0;
tdt = (struct e1000_tdt *)E1000REG(E1000_TDT);
tdt->tdt = 0;
struct e1000_tctl *tctl = (struct e1000_tctl *)E1000REG(E1000_TCTL);
tctl->en = 1;
tctl->psp = 1;
tctl->ct = 0x10;
tctl->cold = 0x40;
struct e1000_tipg *tipg = (struct e1000_tipg *)E1000REG(E1000_TIPG);
tipg->ipgt = 10;
tipg->ipgr1 = 4;
tipg->ipgr2 = 6;
}
int
e1000_transmit(void *data, size_t len)
{
uint32_t current = tdt->tdt;
if(!(tx_desc_array[current].status & E1000_TXD_STAT_DD)) {
return -E_TRANSMIT_RETRY;
}
tx_desc_array[current].length = len;
tx_desc_array[current].status &= ~E1000_TXD_STAT_DD;
tx_desc_array[current].cmd |= (E1000_TXD_CMD_EOP | E1000_TXD_CMD_RS);
memcpy(tx_buffer_array[current], data, len);
uint32_t next = (current + 1) % TXDESCS;
tdt->tdt = next;
return 0;
}
static void
get_ra_address(uint32_t mac[], uint32_t *ral, uint32_t *rah)
{
uint32_t low = 0, high = 0;
int i;
for (i = 0; i < 4; i++) {
low |= mac[i] << (8 * i);
}
for (i = 4; i < 6; i++) {
high |= mac[i] << (8 * i);
}
*ral = low;
*rah = high | E1000_RAH_AV;
}
static void
e1000_receive_init()
{
uint32_t *rdbal = (uint32_t *)E1000REG(E1000_RDBAL);
uint32_t *rdbah = (uint32_t *)E1000REG(E1000_RDBAH);
*rdbal = PADDR(rx_desc_array);
*rdbah = 0;
int i;
for (i = 0; i < RXDESCS; i++) {
rx_desc_array[i].addr = PADDR(rx_buffer_array[i]);
}
struct e1000_rdlen *rdlen = (struct e1000_rdlen *)E1000REG(E1000_RDLEN);
rdlen->len = RXDESCS;
rdh = (struct e1000_rdh *)E1000REG(E1000_RDH);
rdt = (struct e1000_rdt *)E1000REG(E1000_RDT);
rdh->rdh = 0;
rdt->rdt = RXDESCS-1;
uint32_t *rctl = (uint32_t *)E1000REG(E1000_RCTL);
*rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SECRC;
uint32_t *ra = (uint32_t *)E1000REG(E1000_RA);
uint32_t ral, rah;
get_ra_address(E1000_MAC, &ral, &rah);
ra[0] = ral;
ra[1] = rah;
}
int
e1000_receive(void *addr, size_t *len)
{
static int32_t next = 0;
if(!(rx_desc_array[next].status & E1000_RXD_STAT_DD)) {
return -E_RECEIVE_RETRY;
}
if(rx_desc_array[next].errors) {
cprintf("receive errors\n");
return -E_RECEIVE_RETRY;
}
*len = rx_desc_array[next].length;
memcpy(addr, rx_buffer_array[next], *len);
rdt->rdt = (rdt->rdt + 1) % RXDESCS;
next = (next + 1) % RXDESCS;
return 0;
}

View File

@@ -0,0 +1,162 @@
#include <kern/e1000.h>
#include <kern/pmap.h>
#include <inc/string.h>
// LAB 6: Your driver code here
volatile void *bar_va;
#define E1000REG(offset) (void *)(bar_va + offset)
struct e1000_tdh *tdh;
struct e1000_tdt *tdt;
struct e1000_tx_desc tx_desc_array[TXDESCS];
char tx_buffer_array[TXDESCS][TX_PKT_SIZE];
struct e1000_rdh *rdh;
struct e1000_rdt *rdt;
struct e1000_rx_desc rx_desc_array[RXDESCS];
char rx_buffer_array[RXDESCS][RX_PKT_SIZE];
uint32_t E1000_MAC[6] = {0x52, 0x54, 0x00, 0x12, 0x34, 0x56};
int
e1000_attachfn(struct pci_func *pcif)
{
pci_func_enable(pcif);
cprintf("reg_base:%x, reg_size:%x\n", pcif->reg_base[0], pcif->reg_size[0]);
bar_va = mmio_map_region(pcif->reg_base[0], pcif->reg_size[0]);
uint32_t *status_reg = (uint32_t *)E1000REG(E1000_STATUS);
assert(*status_reg == 0x80080783);
e1000_transmit_init();
e1000_receive_init();
/*
* transmit test
*/
// char *data = "transmit test";
// e1000_transmit(data, 13);
return 0;
}
static void
e1000_transmit_init()
{
int i;
for (i = 0; i < TXDESCS; i++) {
tx_desc_array[i].addr = PADDR(tx_buffer_array[i]);
tx_desc_array[i].cmd = 0;
tx_desc_array[i].status |= E1000_TXD_STAT_DD;
}
struct e1000_tdlen *tdlen = (struct e1000_tdlen *)E1000REG(E1000_TDLEN);
tdlen->len = TXDESCS;
uint32_t *tdbal = (uint32_t *)E1000REG(E1000_TDBAL);
*tdbal = PADDR(tx_desc_array);
uint32_t *tdbah = (uint32_t *)E1000REG(E1000_TDBAH);
*tdbah = 0;
tdh = (struct e1000_tdh *)E1000REG(E1000_TDH);
tdh->tdh = 0;
tdt = (struct e1000_tdt *)E1000REG(E1000_TDT);
tdt->tdt = 0;
struct e1000_tctl *tctl = (struct e1000_tctl *)E1000REG(E1000_TCTL);
tctl->en = 1;
tctl->psp = 1;
tctl->ct = 0x10;
tctl->cold = 0x40;
struct e1000_tipg *tipg = (struct e1000_tipg *)E1000REG(E1000_TIPG);
tipg->ipgt = 10;
tipg->ipgr1 = 4;
tipg->ipgr2 = 6;
}
int
e1000_transmit(void *data, size_t len)
{
uint32_t current = tdt->tdt;
if(!(tx_desc_array[current].status & E1000_TXD_STAT_DD)) {
return -E_TRANSMIT_RETRY;
}
tx_desc_array[current].length = len;
tx_desc_array[current].status &= ~E1000_TXD_STAT_DD;
tx_desc_array[current].cmd |= (E1000_TXD_CMD_EOP | E1000_TXD_CMD_RS);
memcpy(tx_buffer_array[current], data, len);
uint32_t next = (current + 1) % TXDESCS;
tdt->tdt = next;
return 0;
}
static void
get_ra_address(uint32_t mac[], uint32_t *ral, uint32_t *rah)
{
uint32_t low = 0, high = 0;
int i;
for (i = 0; i < 4; i++) {
low |= mac[i] << (8 * i);
}
for (i = 4; i < 6; i++) {
high |= mac[i] << (8 * i);
}
*ral = low;
*rah = high | E1000_RAH_AV;
}
static void
e1000_receive_init()
{
uint32_t *rdbal = (uint32_t *)E1000REG(E1000_RDBAL);
uint32_t *rdbah = (uint32_t *)E1000REG(E1000_RDBAH);
*rdbal = PADDR(rx_desc_array);
*rdbah = 0;
int i;
for (i = 0; i < RXDESCS; i++) {
rx_desc_array[i].addr = PADDR(rx_buffer_array[i]);
}
struct e1000_rdlen *rdlen = (struct e1000_rdlen *)E1000REG(E1000_RDLEN);
rdlen->len = RXDESCS;
rdh = (struct e1000_rdh *)E1000REG(E1000_RDH);
rdt = (struct e1000_rdt *)E1000REG(E1000_RDT);
rdh->rdh = 0;
rdt->rdt = RXDESCS-1;
uint32_t *rctl = (uint32_t *)E1000REG(E1000_RCTL);
*rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SECRC;
uint32_t *ra = (uint32_t *)E1000REG(E1000_RA);
uint32_t ral, rah;
get_ra_address(E1000_MAC, &ral, &rah);
ra[0] = ral;
ra[1] = rah;
}
int
e1000_receive(void *addr, size_t *len)
{
static int32_t next = 0;
if(!(rx_desc_array[next].status & E1000_RXD_STAT_DD)) {
return -E_RECEIVE_RETRY;
}
if(rx_desc_array[next].errors) {
cprintf("receive errors\n");
return -E_RECEIVE_RETRY;
}
*len = rx_desc_array[next].length;
memcpy(addr, rx_buffer_array[next], *len);
rdt->rdt = (rdt->rdt + 1) % RXDESCS;
next = (next + 1) % RXDESCS;
return 0;
}

View File

@@ -0,0 +1,327 @@
#include <inc/lib.h>
#include <lwip/sockets.h>
#include <lwip/inet.h>
#define PORT 80
#define VERSION "0.1"
#define HTTP_VERSION "1.0"
#define E_BAD_REQ 1000
#define BUFFSIZE 512
#define MAXPENDING 5 // Max connection requests
struct http_request {
int sock;
char *url;
char *version;
};
struct responce_header {
int code;
char *header;
};
struct responce_header headers[] = {
{ 200, "HTTP/" HTTP_VERSION " 200 OK\r\n"
"Server: jhttpd/" VERSION "\r\n"},
{0, 0},
};
struct error_messages {
int code;
char *msg;
};
struct error_messages errors[] = {
{400, "Bad Request"},
{404, "Not Found"},
};
static void
die(char *m)
{
cprintf("%s\n", m);
exit();
}
static void
req_free(struct http_request *req)
{
free(req->url);
free(req->version);
}
static int
send_header(struct http_request *req, int code)
{
struct responce_header *h = headers;
while (h->code != 0 && h->header!= 0) {
if (h->code == code)
break;
h++;
}
if (h->code == 0)
return -1;
int len = strlen(h->header);
if (write(req->sock, h->header, len) != len) {
die("Failed to send bytes to client");
}
return 0;
}
static int
send_data(struct http_request *req, int fd)
{
// LAB 6: Your code here.
panic("send_data not implemented");
}
static int
send_size(struct http_request *req, off_t size)
{
char buf[64];
int r;
r = snprintf(buf, 64, "Content-Length: %ld\r\n", (long)size);
if (r > 63)
panic("buffer too small!");
if (write(req->sock, buf, r) != r)
return -1;
return 0;
}
static const char*
mime_type(const char *file)
{
//TODO: for now only a single mime type
return "text/html";
}
static int
send_content_type(struct http_request *req)
{
char buf[128];
int r;
const char *type;
type = mime_type(req->url);
if (!type)
return -1;
r = snprintf(buf, 128, "Content-Type: %s\r\n", type);
if (r > 127)
panic("buffer too small!");
if (write(req->sock, buf, r) != r)
return -1;
return 0;
}
static int
send_header_fin(struct http_request *req)
{
const char *fin = "\r\n";
int fin_len = strlen(fin);
if (write(req->sock, fin, fin_len) != fin_len)
return -1;
return 0;
}
// given a request, this function creates a struct http_request
static int
http_request_parse(struct http_request *req, char *request)
{
const char *url;
const char *version;
int url_len, version_len;
if (!req)
return -1;
if (strncmp(request, "GET ", 4) != 0)
return -E_BAD_REQ;
// skip GET
request += 4;
// get the url
url = request;
while (*request && *request != ' ')
request++;
url_len = request - url;
req->url = malloc(url_len + 1);
memmove(req->url, url, url_len);
req->url[url_len] = '\0';
// skip space
request++;
version = request;
while (*request && *request != '\n')
request++;
version_len = request - version;
req->version = malloc(version_len + 1);
memmove(req->version, version, version_len);
req->version[version_len] = '\0';
// no entity parsing
return 0;
}
static int
send_error(struct http_request *req, int code)
{
char buf[512];
int r;
struct error_messages *e = errors;
while (e->code != 0 && e->msg != 0) {
if (e->code == code)
break;
e++;
}
if (e->code == 0)
return -1;
r = snprintf(buf, 512, "HTTP/" HTTP_VERSION" %d %s\r\n"
"Server: jhttpd/" VERSION "\r\n"
"Connection: close"
"Content-type: text/html\r\n"
"\r\n"
"<html><body><p>%d - %s</p></body></html>\r\n",
e->code, e->msg, e->code, e->msg);
if (write(req->sock, buf, r) != r)
return -1;
return 0;
}
static int
send_file(struct http_request *req)
{
int r;
off_t file_size = -1;
int fd;
// open the requested url for reading
// if the file does not exist, send a 404 error using send_error
// if the file is a directory, send a 404 error using send_error
// set file_size to the size of the file
// LAB 6: Your code here.
panic("send_file not implemented");
if ((r = send_header(req, 200)) < 0)
goto end;
if ((r = send_size(req, file_size)) < 0)
goto end;
if ((r = send_content_type(req)) < 0)
goto end;
if ((r = send_header_fin(req)) < 0)
goto end;
r = send_data(req, fd);
end:
close(fd);
return r;
}
static void
handle_client(int sock)
{
struct http_request con_d;
int r;
char buffer[BUFFSIZE];
int received = -1;
struct http_request *req = &con_d;
while (1)
{
// Receive message
if ((received = read(sock, buffer, BUFFSIZE)) < 0)
panic("failed to read");
memset(req, 0, sizeof(*req));
req->sock = sock;
r = http_request_parse(req, buffer);
if (r == -E_BAD_REQ)
send_error(req, 400);
else if (r < 0)
panic("parse failed");
else
send_file(req);
req_free(req);
// no keep alive
break;
}
close(sock);
}
void
umain(int argc, char **argv)
{
int serversock, clientsock;
struct sockaddr_in server, client;
binaryname = "jhttpd";
// Create the TCP socket
if ((serversock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
die("Failed to create socket");
// Construct the server sockaddr_in structure
memset(&server, 0, sizeof(server)); // Clear struct
server.sin_family = AF_INET; // Internet/IP
server.sin_addr.s_addr = htonl(INADDR_ANY); // IP address
server.sin_port = htons(PORT); // server port
// Bind the server socket
if (bind(serversock, (struct sockaddr *) &server,
sizeof(server)) < 0)
{
die("Failed to bind the server socket");
}
// Listen on the server socket
if (listen(serversock, MAXPENDING) < 0)
die("Failed to listen on server socket");
cprintf("Waiting for http connections...\n");
while (1) {
unsigned int clientlen = sizeof(client);
// Wait for client connection
if ((clientsock = accept(serversock,
(struct sockaddr *) &client,
&clientlen)) < 0)
{
die("Failed to accept client connection");
}
handle_client(clientsock);
}
close(serversock);
}

View File

@@ -0,0 +1,65 @@
#include "ns.h"
#include <kern/e1000.h>
extern union Nsipc nsipcbuf;
void
sleep(int msec)
{
unsigned now = sys_time_msec();
unsigned end = now + msec;
if ((int)now < 0 && (int)now > -MAXERROR)
panic("sys_time_msec: %e", (int)now);
if (end < now)
panic("sleep: wrap");
while (sys_time_msec() < end)
sys_yield();
}
void
input(envid_t ns_envid)
{
binaryname = "ns_input";
// LAB 6: Your code here:
// - read a packet from the device driver
// - send it to the network server
// Hint: When you IPC a page to the network server, it will be
// reading from it for a while, so don't immediately receive
// another packet in to the same physical page.
/*
size_t len;
char rev_buf[RX_PACKET_SIZE];
size_t i = 0;
while(1) {
// 阻塞式读
while ( sys_pkt_try_receive(rev_buf, &len) < 0) {
sys_yield();
}
memcpy(nsipcbuf.pkt.jp_data, rev_buf, len);
nsipcbuf.pkt.jp_len = len;
ipc_send(ns_envid, NSREQ_INPUT, &nsipcbuf, PTE_P|PTE_U);
sleep(50);
}
*/
size_t len;
char buf[RX_PKT_SIZE];
while (1) {
if (sys_pkt_recv(buf, &len) < 0) {
continue;
}
memcpy(nsipcbuf.pkt.jp_data, buf, len);
nsipcbuf.pkt.jp_len = len;
ipc_send(ns_envid, NSREQ_INPUT, &nsipcbuf, PTE_P|PTE_U|PTE_W);
sleep(50);
}
}

View File

@@ -0,0 +1,16 @@
#include "ns.h"
extern union Nsipc nsipcbuf;
void
input(envid_t ns_envid)
{
binaryname = "ns_input";
// LAB 6: Your code here:
// - read a packet from the device driver
// - send it to the network server
// Hint: When you IPC a page to the network server, it will be
// reading from it for a while, so don't immediately receive
// another packet in to the same physical page.
}

View File

@@ -0,0 +1,152 @@
// Main public header file for our user-land support library,
// whose code lives in the lib directory.
// This library is roughly our OS's version of a standard C library,
// and is intended to be linked into all user-mode applications
// (NOT the kernel or boot loader).
#ifndef JOS_INC_LIB_H
#define JOS_INC_LIB_H 1
#include <inc/types.h>
#include <inc/stdio.h>
#include <inc/stdarg.h>
#include <inc/string.h>
#include <inc/error.h>
#include <inc/assert.h>
#include <inc/env.h>
#include <inc/memlayout.h>
#include <inc/syscall.h>
#include <inc/trap.h>
#include <inc/fs.h>
#include <inc/fd.h>
#include <inc/args.h>
#include <inc/malloc.h>
#include <inc/ns.h>
#define USED(x) (void)(x)
// main user program
void umain(int argc, char **argv);
// libmain.c or entry.S
extern const char *binaryname;
extern const volatile struct Env *thisenv;
extern const volatile struct Env envs[NENV];
extern const volatile struct PageInfo pages[];
// exit.c
void exit(void);
// pgfault.c
void set_pgfault_handler(void (*handler)(struct UTrapframe *utf));
// readline.c
char* readline(const char *buf);
// syscall.c
void sys_cputs(const char *string, size_t len);
int sys_cgetc(void);
envid_t sys_getenvid(void);
int sys_env_destroy(envid_t);
void sys_yield(void);
static envid_t sys_exofork(void);
int sys_env_set_status(envid_t env, int status);
int sys_env_set_trapframe(envid_t env, struct Trapframe *tf);
int sys_env_set_pgfault_upcall(envid_t env, void *upcall);
int sys_page_alloc(envid_t env, void *pg, int perm);
int sys_page_map(envid_t src_env, void *src_pg,
envid_t dst_env, void *dst_pg, int perm);
int sys_page_unmap(envid_t env, void *pg);
int sys_ipc_try_send(envid_t to_env, uint32_t value, void *pg, int perm);
int sys_ipc_recv(void *rcv_pg);
unsigned int sys_time_msec(void);
// This must be inlined. Exercise for reader: why?
static inline envid_t __attribute__((always_inline))
sys_exofork(void)
{
envid_t ret;
asm volatile("int %2"
: "=a" (ret)
: "a" (SYS_exofork), "i" (T_SYSCALL));
return ret;
}
// ipc.c
void ipc_send(envid_t to_env, uint32_t value, void *pg, int perm);
int32_t ipc_recv(envid_t *from_env_store, void *pg, int *perm_store);
envid_t ipc_find_env(enum EnvType type);
// fork.c
#define PTE_SHARE 0x400
envid_t fork(void);
envid_t sfork(void); // Challenge!
// fd.c
int close(int fd);
ssize_t read(int fd, void *buf, size_t nbytes);
ssize_t write(int fd, const void *buf, size_t nbytes);
int seek(int fd, off_t offset);
void close_all(void);
ssize_t readn(int fd, void *buf, size_t nbytes);
int dup(int oldfd, int newfd);
int fstat(int fd, struct Stat *statbuf);
int stat(const char *path, struct Stat *statbuf);
// file.c
int open(const char *path, int mode);
int ftruncate(int fd, off_t size);
int remove(const char *path);
int sync(void);
// pageref.c
int pageref(void *addr);
// sockets.c
int accept(int s, struct sockaddr *addr, socklen_t *addrlen);
int bind(int s, struct sockaddr *name, socklen_t namelen);
int shutdown(int s, int how);
int connect(int s, const struct sockaddr *name, socklen_t namelen);
int listen(int s, int backlog);
int socket(int domain, int type, int protocol);
// nsipc.c
int nsipc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
int nsipc_bind(int s, struct sockaddr *name, socklen_t namelen);
int nsipc_shutdown(int s, int how);
int nsipc_close(int s);
int nsipc_connect(int s, const struct sockaddr *name, socklen_t namelen);
int nsipc_listen(int s, int backlog);
int nsipc_recv(int s, void *mem, int len, unsigned int flags);
int nsipc_send(int s, const void *buf, int size, unsigned int flags);
int nsipc_socket(int domain, int type, int protocol);
// spawn.c
envid_t spawn(const char *program, const char **argv);
envid_t spawnl(const char *program, const char *arg0, ...);
// console.c
void cputchar(int c);
int getchar(void);
int iscons(int fd);
int opencons(void);
// pipe.c
int pipe(int pipefds[2]);
int pipeisclosed(int pipefd);
// wait.c
void wait(envid_t env);
/* File open modes */
#define O_RDONLY 0x0000 /* open for reading only */
#define O_WRONLY 0x0001 /* open for writing only */
#define O_RDWR 0x0002 /* open for reading and writing */
#define O_ACCMODE 0x0003 /* mask for above modes */
#define O_CREAT 0x0100 /* create if nonexistent */
#define O_TRUNC 0x0200 /* truncate to zero length */
#define O_EXCL 0x0400 /* error if already exists */
#define O_MKDIR 0x0800 /* create directory, not regular file */
#endif // !JOS_INC_LIB_H

View File

@@ -0,0 +1,27 @@
#include "ns.h"
extern union Nsipc nsipcbuf;
void
output(envid_t ns_envid)
{
binaryname = "ns_output";
envid_t envid;
int perm;
int32_t req;
// LAB 6: Your code here:
// - read a packet from the network server
while(1) {
req = ipc_recv(&envid, (void *) &nsipcbuf, &perm);
if (req != NSREQ_OUTPUT)
continue;
struct jif_pkt *pkt = &(nsipcbuf.pkt);
while (sys_pkt_try_send(pkt->jp_data, pkt->jp_len) < 0) {
sys_yield();
}
}
}

View File

@@ -0,0 +1,13 @@
#include "ns.h"
extern union Nsipc nsipcbuf;
void
output(envid_t ns_envid)
{
binaryname = "ns_output";
// LAB 6: Your code here:
// - read a packet from the network server
// - send the packet to the device driver
}

View File

@@ -0,0 +1,262 @@
#include <inc/x86.h>
#include <inc/assert.h>
#include <inc/string.h>
#include <kern/pci.h>
#include <kern/pcireg.h>
#include <kern/e1000.h>
// Flag to do "lspci" at bootup
static int pci_show_devs = 1;
static int pci_show_addrs = 0;
// PCI "configuration mechanism one"
static uint32_t pci_conf1_addr_ioport = 0x0cf8;
static uint32_t pci_conf1_data_ioport = 0x0cfc;
// Forward declarations
static int pci_bridge_attach(struct pci_func *pcif);
int pci_e1000_attach(struct pci_func * pcif);
// PCI driver table
struct pci_driver {
uint32_t key1, key2;
int (*attachfn) (struct pci_func *pcif);
};
// pci_attach_class matches the class and subclass of a PCI device
struct pci_driver pci_attach_class[] = {
{ PCI_CLASS_BRIDGE, PCI_SUBCLASS_BRIDGE_PCI, &pci_bridge_attach },
{ 0, 0, 0 },
};
// pci_attach_vendor matches the vendor ID and device ID of a PCI device. key1
// and key2 should be the vendor ID and device ID respectively
struct pci_driver pci_attach_vendor[] = {
{ PCI_E1000_VENDOR_ID, PCI_E1000_DEVICE_ID, &pci_e1000_attach},
{ 0, 0, 0 },
};
static void
pci_conf1_set_addr(uint32_t bus,
uint32_t dev,
uint32_t func,
uint32_t offset)
{
assert(bus < 256);
assert(dev < 32);
assert(func < 8);
assert(offset < 256);
assert((offset & 0x3) == 0);
uint32_t v = (1 << 31) | // config-space
(bus << 16) | (dev << 11) | (func << 8) | (offset);
outl(pci_conf1_addr_ioport, v);
}
static uint32_t
pci_conf_read(struct pci_func *f, uint32_t off)
{
pci_conf1_set_addr(f->bus->busno, f->dev, f->func, off);
return inl(pci_conf1_data_ioport);
}
static void
pci_conf_write(struct pci_func *f, uint32_t off, uint32_t v)
{
pci_conf1_set_addr(f->bus->busno, f->dev, f->func, off);
outl(pci_conf1_data_ioport, v);
}
static int __attribute__((warn_unused_result))
pci_attach_match(uint32_t key1, uint32_t key2,
struct pci_driver *list, struct pci_func *pcif)
{
uint32_t i;
for (i = 0; list[i].attachfn; i++) {
if (list[i].key1 == key1 && list[i].key2 == key2) {
int r = list[i].attachfn(pcif);
if (r > 0)
return r;
if (r < 0)
cprintf("pci_attach_match: attaching "
"%x.%x (%p): e\n",
key1, key2, list[i].attachfn, r);
}
}
return 0;
}
static int
pci_attach(struct pci_func *f)
{
return
pci_attach_match(PCI_CLASS(f->dev_class),
PCI_SUBCLASS(f->dev_class),
&pci_attach_class[0], f) ||
pci_attach_match(PCI_VENDOR(f->dev_id),
PCI_PRODUCT(f->dev_id),
&pci_attach_vendor[0], f);
}
static const char *pci_class[] =
{
[0x0] = "Unknown",
[0x1] = "Storage controller",
[0x2] = "Network controller",
[0x3] = "Display controller",
[0x4] = "Multimedia device",
[0x5] = "Memory controller",
[0x6] = "Bridge device",
};
static void
pci_print_func(struct pci_func *f)
{
const char *class = pci_class[0];
if (PCI_CLASS(f->dev_class) < ARRAY_SIZE(pci_class))
class = pci_class[PCI_CLASS(f->dev_class)];
cprintf("PCI: %02x:%02x.%d: %04x:%04x: class: %x.%x (%s) irq: %d\n",
f->bus->busno, f->dev, f->func,
PCI_VENDOR(f->dev_id), PCI_PRODUCT(f->dev_id),
PCI_CLASS(f->dev_class), PCI_SUBCLASS(f->dev_class), class,
f->irq_line);
}
static int
pci_scan_bus(struct pci_bus *bus)
{
int totaldev = 0;
struct pci_func df;
memset(&df, 0, sizeof(df));
df.bus = bus;
for (df.dev = 0; df.dev < 32; df.dev++) {
uint32_t bhlc = pci_conf_read(&df, PCI_BHLC_REG);
if (PCI_HDRTYPE_TYPE(bhlc) > 1) // Unsupported or no device
continue;
totaldev++;
struct pci_func f = df;
for (f.func = 0; f.func < (PCI_HDRTYPE_MULTIFN(bhlc) ? 8 : 1);
f.func++) {
struct pci_func af = f;
af.dev_id = pci_conf_read(&f, PCI_ID_REG);
if (PCI_VENDOR(af.dev_id) == 0xffff)
continue;
uint32_t intr = pci_conf_read(&af, PCI_INTERRUPT_REG);
af.irq_line = PCI_INTERRUPT_LINE(intr);
af.dev_class = pci_conf_read(&af, PCI_CLASS_REG);
if (pci_show_devs)
pci_print_func(&af);
pci_attach(&af);
}
}
return totaldev;
}
static int
pci_bridge_attach(struct pci_func *pcif)
{
uint32_t ioreg = pci_conf_read(pcif, PCI_BRIDGE_STATIO_REG);
uint32_t busreg = pci_conf_read(pcif, PCI_BRIDGE_BUS_REG);
if (PCI_BRIDGE_IO_32BITS(ioreg)) {
cprintf("PCI: %02x:%02x.%d: 32-bit bridge IO not supported.\n",
pcif->bus->busno, pcif->dev, pcif->func);
return 0;
}
struct pci_bus nbus;
memset(&nbus, 0, sizeof(nbus));
nbus.parent_bridge = pcif;
nbus.busno = (busreg >> PCI_BRIDGE_BUS_SECONDARY_SHIFT) & 0xff;
if (pci_show_devs)
cprintf("PCI: %02x:%02x.%d: bridge to PCI bus %d--%d\n",
pcif->bus->busno, pcif->dev, pcif->func,
nbus.busno,
(busreg >> PCI_BRIDGE_BUS_SUBORDINATE_SHIFT) & 0xff);
pci_scan_bus(&nbus);
return 1;
}
// External PCI subsystem interface
void
pci_func_enable(struct pci_func *f)
{
pci_conf_write(f, PCI_COMMAND_STATUS_REG,
PCI_COMMAND_IO_ENABLE |
PCI_COMMAND_MEM_ENABLE |
PCI_COMMAND_MASTER_ENABLE);
uint32_t bar_width;
uint32_t bar;
for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END;
bar += bar_width)
{
uint32_t oldv = pci_conf_read(f, bar);
bar_width = 4;
pci_conf_write(f, bar, 0xffffffff);
uint32_t rv = pci_conf_read(f, bar);
if (rv == 0)
continue;
int regnum = PCI_MAPREG_NUM(bar);
uint32_t base, size;
if (PCI_MAPREG_TYPE(rv) == PCI_MAPREG_TYPE_MEM) {
if (PCI_MAPREG_MEM_TYPE(rv) == PCI_MAPREG_MEM_TYPE_64BIT)
bar_width = 8;
size = PCI_MAPREG_MEM_SIZE(rv);
base = PCI_MAPREG_MEM_ADDR(oldv);
if (pci_show_addrs)
cprintf(" mem region %d: %d bytes at 0x%x\n",
regnum, size, base);
} else {
size = PCI_MAPREG_IO_SIZE(rv);
base = PCI_MAPREG_IO_ADDR(oldv);
if (pci_show_addrs)
cprintf(" io region %d: %d bytes at 0x%x\n",
regnum, size, base);
}
pci_conf_write(f, bar, oldv);
f->reg_base[regnum] = base;
f->reg_size[regnum] = size;
if (size && !base)
cprintf("PCI device %02x:%02x.%d (%04x:%04x) "
"may be misconfigured: "
"region %d: base 0x%x, size %d\n",
f->bus->busno, f->dev, f->func,
PCI_VENDOR(f->dev_id), PCI_PRODUCT(f->dev_id),
regnum, base, size);
}
cprintf("PCI function %02x:%02x.%d (%04x:%04x) enabled\n",
f->bus->busno, f->dev, f->func,
PCI_VENDOR(f->dev_id), PCI_PRODUCT(f->dev_id));
}
int
pci_init(void)
{
static struct pci_bus root_bus;
memset(&root_bus, 0, sizeof(root_bus));
return pci_scan_bus(&root_bus);
}

View File

@@ -0,0 +1,24 @@
#ifndef JOS_INC_SYSCALL_H
#define JOS_INC_SYSCALL_H
/* system call numbers */
enum {
SYS_cputs = 0,
SYS_cgetc,
SYS_getenvid,
SYS_env_destroy,
SYS_page_alloc,
SYS_page_map,
SYS_page_unmap,
SYS_exofork,
SYS_env_set_status,
SYS_env_set_trapframe,
SYS_env_set_pgfault_upcall,
SYS_yield,
SYS_ipc_try_send,
SYS_ipc_recv,
SYS_time_msec,
NSYSCALLS
};
#endif /* !JOS_INC_SYSCALL_H */

View File

@@ -0,0 +1,124 @@
// System call stubs.
#include <inc/syscall.h>
#include <inc/lib.h>
static inline int32_t
syscall(int num, int check, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5)
{
int32_t ret;
// Generic system call: pass system call number in AX,
// up to five parameters in DX, CX, BX, DI, SI.
// Interrupt kernel with T_SYSCALL.
//
// The "volatile" tells the assembler not to optimize
// this instruction away just because we don't use the
// return value.
//
// The last clause tells the assembler that this can
// potentially change the condition codes and arbitrary
// memory locations.
asm volatile("int %1\n"
: "=a" (ret)
: "i" (T_SYSCALL),
"a" (num),
"d" (a1),
"c" (a2),
"b" (a3),
"D" (a4),
"S" (a5)
: "cc", "memory");
if(check && ret > 0)
panic("syscall %d returned %d (> 0)", num, ret);
return ret;
}
void
sys_cputs(const char *s, size_t len)
{
syscall(SYS_cputs, 0, (uint32_t)s, len, 0, 0, 0);
}
int
sys_cgetc(void)
{
return syscall(SYS_cgetc, 0, 0, 0, 0, 0, 0);
}
int
sys_env_destroy(envid_t envid)
{
return syscall(SYS_env_destroy, 1, envid, 0, 0, 0, 0);
}
envid_t
sys_getenvid(void)
{
return syscall(SYS_getenvid, 0, 0, 0, 0, 0, 0);
}
void
sys_yield(void)
{
syscall(SYS_yield, 0, 0, 0, 0, 0, 0);
}
int
sys_page_alloc(envid_t envid, void *va, int perm)
{
return syscall(SYS_page_alloc, 1, envid, (uint32_t) va, perm, 0, 0);
}
int
sys_page_map(envid_t srcenv, void *srcva, envid_t dstenv, void *dstva, int perm)
{
return syscall(SYS_page_map, 1, srcenv, (uint32_t) srcva, dstenv, (uint32_t) dstva, perm);
}
int
sys_page_unmap(envid_t envid, void *va)
{
return syscall(SYS_page_unmap, 1, envid, (uint32_t) va, 0, 0, 0);
}
// sys_exofork is inlined in lib.h
int
sys_env_set_status(envid_t envid, int status)
{
return syscall(SYS_env_set_status, 1, envid, status, 0, 0, 0);
}
int
sys_env_set_trapframe(envid_t envid, struct Trapframe *tf)
{
return syscall(SYS_env_set_trapframe, 1, envid, (uint32_t) tf, 0, 0, 0);
}
int
sys_env_set_pgfault_upcall(envid_t envid, void *upcall)
{
return syscall(SYS_env_set_pgfault_upcall, 1, envid, (uint32_t) upcall, 0, 0, 0);
}
int
sys_ipc_try_send(envid_t envid, uint32_t value, void *srcva, int perm)
{
return syscall(SYS_ipc_try_send, 0, envid, value, (uint32_t) srcva, perm, 0);
}
int
sys_ipc_recv(void *dstva)
{
return syscall(SYS_ipc_recv, 1, (uint32_t)dstva, 0, 0, 0, 0);
}
unsigned int
sys_time_msec(void)
{
return (unsigned int) syscall(SYS_time_msec, 0, 0, 0, 0, 0, 0);
}

View File

@@ -0,0 +1,498 @@
/* See COPYRIGHT for copyright information. */
#include <inc/x86.h>
#include <inc/error.h>
#include <inc/string.h>
#include <inc/assert.h>
#include <kern/env.h>
#include <kern/pmap.h>
#include <kern/trap.h>
#include <kern/syscall.h>
#include <kern/console.h>
#include <kern/sched.h>
#include <kern/time.h>
// Print a string to the system console.
// The string is exactly 'len' characters long.
// Destroys the environment on memory errors.
static void
sys_cputs(const char *s, size_t len)
{
// Check that the user has permission to read memory [s, s+len).
// Destroy the environment if not.
// LAB 3: Your code here.
user_mem_assert(curenv, (const void *) s, len, 0);
// Print the string supplied by the user.
cprintf("%.*s", len, s);
}
// Read a character from the system console without blocking.
// Returns the character, or 0 if there is no input waiting.
static int
sys_cgetc(void)
{
return cons_getc();
}
// Returns the current environment's envid.
static envid_t
sys_getenvid(void)
{
return curenv->env_id;
}
// Destroy a given environment (possibly the currently running environment).
//
// Returns 0 on success, < 0 on error. Errors are:
// -E_BAD_ENV if environment envid doesn't currently exist,
// or the caller doesn't have permission to change envid.
static int
sys_env_destroy(envid_t envid)
{
int r;
struct Env *e;
if ((r = envid2env(envid, &e, 1)) < 0)
return r;
if (e == curenv)
cprintf("[%08x] exiting gracefully\n", curenv->env_id);
else
cprintf("[%08x] destroying %08x\n", curenv->env_id, e->env_id);
env_destroy(e);
return 0;
}
// Deschedule current environment and pick a different one to run.
static void
sys_yield(void)
{
sched_yield();
}
// Allocate a new environment.
// Returns envid of new environment, or < 0 on error. Errors are:
// -E_NO_FREE_ENV if no free environment is available.
// -E_NO_MEM on memory exhaustion.
static envid_t
sys_exofork(void)
{
// Create the new environment with env_alloc(), from kern/env.c.
// It should be left as env_alloc created it, except that
// status is set to ENV_NOT_RUNNABLE, and the register set is copied
// from the current environment -- but tweaked so sys_exofork
// will appear to return 0.
// LAB 4: Your code here.
struct Env *newenv;
int32_t ret;
if ((ret = env_alloc(&newenv, sys_getenvid())) < 0) {
// 两个函数的返回值是一样的
return ret;
}
newenv->env_status = ENV_NOT_RUNNABLE;
newenv->env_tf = curenv->env_tf;
// newenv的返回值为0, 实现子进程返回0值
newenv->env_tf.tf_regs.reg_eax = 0;
// 返回值存放在eax中
return newenv->env_id;
// panic("sys_exofork not implemented");
}
// Set envid's env_status to status, which must be ENV_RUNNABLE
// or ENV_NOT_RUNNABLE.
//
// Returns 0 on success, < 0 on error. Errors are:
// -E_BAD_ENV if environment envid doesn't currently exist,
// or the caller doesn't have permission to change envid.
// -E_INVAL if status is not a valid status for an environment.
static int
sys_env_set_status(envid_t envid, int status)
{
// Hint: Use the 'envid2env' function from kern/env.c to translate an
// envid to a struct Env.
// You should set envid2env's third argument to 1, which will
// check whether the current environment has permission to set
// envid's status.
// LAB 4: Your code here.
struct Env *e;
if (envid2env(envid, &e, 1)) return -E_BAD_ENV;
if (status != ENV_NOT_RUNNABLE && status != ENV_RUNNABLE)
return -E_INVAL;
e->env_status = status;
return 0;
}
// Set envid's trap frame to 'tf'.
// tf is modified to make sure that user environments always run at code
// protection level 3 (CPL 3), interrupts enabled, and IOPL of 0.
//
// Returns 0 on success, < 0 on error. Errors are:
// -E_BAD_ENV if environment envid doesn't currently exist,
// or the caller doesn't have permission to change envid.
static int
sys_env_set_trapframe(envid_t envid, struct Trapframe *tf)
{
// LAB 5: Your code here.
// Remember to check whether the user has supplied us with a good
// address!
struct Env *env;
int r;
if ( (r = envid2env(envid, &env, 1)) < 0)
return r;
// 什么时候会出现没有权限访问的问题?
user_mem_assert(env, tf, sizeof(struct Trapframe), PTE_U);
// 直接整个结构体也是可以赋值的
// tf->tf_cs |= (GD_UT | 0x3);
tf->tf_eflags |= FL_IF;
// 普通进程无I/O权限
tf->tf_eflags &= ~FL_IOPL_MASK;
env->env_tf = *tf;
return 0;
}
// Set the page fault upcall for 'envid' by modifying the corresponding struct
// Env's 'env_pgfault_upcall' field. When 'envid' causes a page fault, the
// kernel will push a fault record onto the exception stack, then branch to
// 'func'.
//
// Returns 0 on success, < 0 on error. Errors are:
// -E_BAD_ENV if environment envid doesn't currently exist,
// or the caller doesn't have permission to change envid.
static int
sys_env_set_pgfault_upcall(envid_t envid, void *func)
{
// LAB 4: Your code here.
struct Env *e;
if (envid2env(envid, &e, 1))
return -E_BAD_ENV;
// cprintf("set pgfault upcall\n");
e->env_pgfault_upcall = func;
return 0;
// panic("sys_env_set_pgfault_upcall not implemented");
}
// Allocate a page of memory and map it at 'va' with permission
// 'perm' in the address space of 'envid'.
// The page's contents are set to 0.
// If a page is already mapped at 'va', that page is unmapped as a
// side effect.
//
// perm -- PTE_U | PTE_P must be set, PTE_AVAIL | PTE_W may or may not be set,
// but no other bits may be set. See PTE_SYSCALL in inc/mmu.h.
//
// Return 0 on success, < 0 on error. Errors are:
// -E_BAD_ENV if environment envid doesn't currently exist,
// or the caller doesn't have permission to change envid.
// -E_INVAL if va >= UTOP, or va is not page-aligned.
// -E_INVAL if perm is inappropriate (see above).
// -E_NO_MEM if there's no memory to allocate the new page,
// or to allocate any necessary page tables.
static int
sys_page_alloc(envid_t envid, void *va, int perm)
{
// Hint: This function is a wrapper around page_alloc() and
// page_insert() from kern/pmap.c.
// Most of the new code you write should be to check the
// parameters for correctness.
// If page_insert() fails, remember to free the page you
// allocated!
// LAB 4: Your code here.
int ret = 0;
struct Env *env;
if ((ret = envid2env(envid, &env, 1)) < 0)
return -E_BAD_ENV;
if((uintptr_t)va >= UTOP || PGOFF(va))
return -E_INVAL;
if ((perm & PTE_U) == 0 || (perm & PTE_P) == 0)
return -E_INVAL;
if (perm & ~PTE_SYSCALL)
return -E_INVAL;
struct PageInfo *pp = page_alloc(ALLOC_ZERO);
if(!pp)
return -E_NO_MEM;
if (page_insert(env->env_pgdir, pp, va, perm) < 0)
return -E_NO_MEM;
return 0;
// panic("sys_page_alloc not implemented");
}
// Map the page of memory at 'srcva' in srcenvid's address space
// at 'dstva' in dstenvid's address space with permission 'perm'.
// Perm has the same restrictions as in sys_page_alloc, except
// that it also must not grant write access to a read-only
// page.
//
// Return 0 on success, < 0 on error. Errors are:
// -E_BAD_ENV if srcenvid and/or dstenvid doesn't currently exist,
// or the caller doesn't have permission to change one of them.
// -E_INVAL if srcva >= UTOP or srcva is not page-aligned,
// or dstva >= UTOP or dstva is not page-aligned.
// -E_INVAL is srcva is not mapped in srcenvid's address space.
// -E_INVAL if perm is inappropriate (see sys_page_alloc).
// -E_INVAL if (perm & PTE_W), but srcva is read-only in srcenvid's
// address space.
// -E_NO_MEM if there's no memory to allocate any necessary page tables.
static int
sys_page_map(envid_t srcenvid, void *srcva,
envid_t dstenvid, void *dstva, int perm)
{
// Hint: This function is a wrapper around page_lookup() and
// page_insert() from kern/pmap.c.
// Again, most of the new code you write should be to check the
// parameters for correctness.
// Use the third argument to page_lookup() to
// check the current permissions on the page.
// LAB 4: Your code here.
int ret = 0;
struct Env *srcenv, *dstenv;
struct PageInfo *srcpp, *dstpp;
pte_t *pte;
if ((envid2env(srcenvid, &srcenv, 1) < 0 )|| ( envid2env(dstenvid, &dstenv, 1) < 0))
return -E_BAD_ENV;
if ((uintptr_t)srcva >= UTOP || PGOFF(srcva) || (uintptr_t)dstva >= UTOP || PGOFF(dstva))
return -E_INVAL;
if ( (perm & PTE_U) == 0 || (perm & PTE_P) == 0 || (perm & ~PTE_SYSCALL))
return -E_INVAL;
if (!(srcpp = page_lookup(srcenv->env_pgdir, srcva, &pte)))
return -E_INVAL;
if ((perm & PTE_W) && ((*pte & PTE_W) == 0))
return -E_INVAL;
if (page_insert(dstenv->env_pgdir, srcpp, dstva, perm) < 0)
return -E_NO_MEM;
return 0;
// panic("sys_page_map not implemented");
}
// Unmap the page of memory at 'va' in the address space of 'envid'.
// If no page is mapped, the function silently succeeds.
//
// Return 0 on success, < 0 on error. Errors are:
// -E_BAD_ENV if environment envid doesn't currently exist,
// or the caller doesn't have permission to change envid.
// -E_INVAL if va >= UTOP, or va is not page-aligned.
static int
sys_page_unmap(envid_t envid, void *va)
{
// Hint: This function is a wrapper around page_remove().
// LAB 4: Your code here.
int ret = 0;
struct Env *env;
if ((ret = envid2env(envid, &env, 1)) < 0)
return -E_BAD_ENV;
if ((uintptr_t)va >= UTOP || PGOFF(va))
return -E_INVAL;
page_remove(env->env_pgdir, va);
return 0;
// panic("sys_page_unmap not implemented");
}
// Try to send 'value' to the target env 'envid'.
// If srcva < UTOP, then also send page currently mapped at 'srcva',
// so that receiver gets a duplicate mapping of the same page.
//
// The send fails with a return value of -E_IPC_NOT_RECV if the
// target is not blocked, waiting for an IPC.
//
// The send also can fail for the other reasons listed below.
//
// Otherwise, the send succeeds, and the target's ipc fields are
// updated as follows:
// env_ipc_recving is set to 0 to block future sends;
// env_ipc_from is set to the sending envid;
// env_ipc_value is set to the 'value' parameter;
// env_ipc_perm is set to 'perm' if a page was transferred, 0 otherwise.
// The target environment is marked runnable again, returning 0
// from the paused sys_ipc_recv system call. (Hint: does the
// sys_ipc_recv function ever actually return?)
//
// If the sender wants to send a page but the receiver isn't asking for one,
// then no page mapping is transferred, but no error occurs.
// The ipc only happens when no errors occur.
//
// Returns 0 on success, < 0 on error.
// Errors are:
// -E_BAD_ENV if environment envid doesn't currently exist.
// (No need to check permissions.)
// -E_IPC_NOT_RECV if envid is not currently blocked in sys_ipc_recv,
// or another environment managed to send first.
// -E_INVAL if srcva < UTOP but srcva is not page-aligned.
// -E_INVAL if srcva < UTOP and perm is inappropriate
// (see sys_page_alloc).
// -E_INVAL if srcva < UTOP but srcva is not mapped in the caller's
// address space.
// -E_INVAL if (perm & PTE_W), but srcva is read-only in the
// current environment's address space.
// -E_NO_MEM if there's not enough memory to map srcva in envid's
// address space.
static int
sys_ipc_try_send(envid_t envid, uint32_t value, void *srcva, unsigned perm)
{
// LAB 4: Your code here.
struct Env *dstenv;
pte_t *pte;
struct PageInfo *pp;
int r;
if ( (r = envid2env( envid, &dstenv, 0)) < 0)
return r;
// 不处于等待接收状态, 或有进程已经请求发送数据
if ( (dstenv->env_ipc_recving != true) || dstenv->env_ipc_from != 0)
return -E_IPC_NOT_RECV;
if ((uint32_t)srcva < UTOP) {
if ( PGOFF(srcva))
return -E_INVAL;
if ( !(perm & PTE_P ) || !(perm & PTE_U) )
return -E_INVAL;
if (perm & (~ PTE_SYSCALL))
return -E_INVAL;
if ((pp = page_lookup(curenv->env_pgdir, srcva, &pte)) == NULL )
return -E_INVAL;
if ((perm & PTE_W) && !(*pte & PTE_W) )
return -E_INVAL;
// 接收进程愿意接收一个页
if (dstenv->env_ipc_dstva) {
// 开始映射
if( (r = page_insert(dstenv->env_pgdir, pp, dstenv->env_ipc_dstva, perm)) < 0)
return r;
dstenv->env_ipc_perm = perm;
}
}
dstenv->env_ipc_from = curenv->env_id;
dstenv->env_ipc_recving = false;
dstenv->env_ipc_value = value;
dstenv->env_status = ENV_RUNNABLE;
// 返回值
dstenv->env_tf.tf_regs.reg_eax = 0;
return 0;
//panic("sys_ipc_try_send not implemented");
}
// Block until a value is ready. Record that you want to receive
// using the env_ipc_recving and env_ipc_dstva fields of struct Env,
// mark yourself not runnable, and then give up the CPU.
//
// If 'dstva' is < UTOP, then you are willing to receive a page of data.
// 'dstva' is the virtual address at which the sent page should be mapped.
//
// This function only returns on error, but the system call will eventually
// return 0 on success.
// Return < 0 on error. Errors are:
// -E_INVAL if dstva < UTOP but dstva is not page-aligned.
static int
sys_ipc_recv(void *dstva)
{
// LAB 4: Your code here.
if ((uint32_t) dstva < UTOP ) {
if (PGOFF(dstva))
return -E_INVAL;
}
// 大于小于都可以赋值为desva。
curenv->env_ipc_dstva = dstva;
curenv->env_status = ENV_NOT_RUNNABLE;
curenv->env_ipc_recving = true;
curenv->env_ipc_from = 0;
sched_yield();
// panic("sys_ipc_recv not implemented");
return 0;
}
// Return the current time.
static int
sys_time_msec(void)
{
// LAB 6: Your code here.
return time_msec();
// panic("sys_time_msec not implemented");
}
// Dispatches to the correct kernel function, passing the arguments.
int32_t
syscall(uint32_t syscallno, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5)
{
// Call the function corresponding to the 'syscallno' parameter.
// Return any appropriate return value.
// LAB 3: Your code here.
switch (syscallno) {
case SYS_cputs:
sys_cputs((const char*)a1, a2);
break;
case SYS_cgetc:
return sys_cgetc();
case SYS_getenvid:
return sys_getenvid();
case SYS_env_destroy:
return sys_env_destroy(a1);
case SYS_yield:
sys_yield();
break;
case SYS_page_alloc:
return sys_page_alloc((envid_t)a1, (void * )a2, (int )a3);
case SYS_env_set_pgfault_upcall:
return sys_env_set_pgfault_upcall((envid_t) a1, (void *) a2);
case SYS_page_map:
return sys_page_map((envid_t) a1, (void *) a2, (envid_t) a3, (void *) a4, (int) a5);
case SYS_page_unmap:
return sys_page_unmap((envid_t) a1, (void *) a2);
case SYS_exofork:
return sys_exofork();
case SYS_env_set_status:
return sys_env_set_status((envid_t) a1, (int) a2);
case SYS_ipc_recv:
return sys_ipc_recv( (void *) a1);
case SYS_ipc_try_send:
return sys_ipc_try_send((envid_t) a1, (uint32_t) a2, (void *) a3, (int) a4);
case SYS_env_set_trapframe:
return sys_env_set_trapframe((envid_t) a1, (struct Trapframe *) a2);
case SYS_time_msec:
return sys_time_msec();
case NSYSCALLS:
return -E_INVAL;
default:
return -E_INVAL;
}
return 0;
}

View File

@@ -0,0 +1,139 @@
// System call stubs.
#include <inc/syscall.h>
#include <inc/lib.h>
static inline int32_t
syscall(int num, int check, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5)
{
int32_t ret;
// Generic system call: pass system call number in AX,
// up to five parameters in DX, CX, BX, DI, SI.
// Interrupt kernel with T_SYSCALL.
//
// The "volatile" tells the assembler not to optimize
// this instruction away just because we don't use the
// return value.
//
// The last clause tells the assembler that this can
// potentially change the condition codes and arbitrary
// memory locations.
asm volatile("int %1\n"
: "=a" (ret)
: "i" (T_SYSCALL),
"a" (num),
"d" (a1),
"c" (a2),
"b" (a3),
"D" (a4),
"S" (a5)
: "cc", "memory");
if(check && ret > 0)
panic("syscall %d returned %d (> 0)", num, ret);
return ret;
}
void
sys_cputs(const char *s, size_t len)
{
syscall(SYS_cputs, 0, (uint32_t)s, len, 0, 0, 0);
}
int
sys_cgetc(void)
{
return syscall(SYS_cgetc, 0, 0, 0, 0, 0, 0);
}
int
sys_env_destroy(envid_t envid)
{
return syscall(SYS_env_destroy, 1, envid, 0, 0, 0, 0);
}
envid_t
sys_getenvid(void)
{
return syscall(SYS_getenvid, 0, 0, 0, 0, 0, 0);
}
void
sys_yield(void)
{
syscall(SYS_yield, 0, 0, 0, 0, 0, 0);
}
int
sys_page_alloc(envid_t envid, void *va, int perm)
{
return syscall(SYS_page_alloc, 1, envid, (uint32_t) va, perm, 0, 0);
}
int
sys_page_map(envid_t srcenv, void *srcva, envid_t dstenv, void *dstva, int perm)
{
return syscall(SYS_page_map, 1, srcenv, (uint32_t) srcva, dstenv, (uint32_t) dstva, perm);
}
int
sys_page_unmap(envid_t envid, void *va)
{
return syscall(SYS_page_unmap, 1, envid, (uint32_t) va, 0, 0, 0);
}
// sys_exofork is inlined in lib.h
int
sys_env_set_status(envid_t envid, int status)
{
return syscall(SYS_env_set_status, 1, envid, status, 0, 0, 0);
}
int
sys_env_set_trapframe(envid_t envid, struct Trapframe *tf)
{
return syscall(SYS_env_set_trapframe, 1, envid, (uint32_t) tf, 0, 0, 0);
}
int
sys_env_set_pgfault_upcall(envid_t envid, void *upcall)
{
return syscall(SYS_env_set_pgfault_upcall, 1, envid, (uint32_t) upcall, 0, 0, 0);
}
int
sys_ipc_try_send(envid_t envid, uint32_t value, void *srcva, int perm)
{
return syscall(SYS_ipc_try_send, 0, envid, value, (uint32_t) srcva, perm, 0);
}
int
sys_ipc_recv(void *dstva)
{
return syscall(SYS_ipc_recv, 1, (uint32_t)dstva, 0, 0, 0, 0);
}
unsigned int
sys_time_msec(void)
{
return (unsigned int) syscall(SYS_time_msec, 0, 0, 0, 0, 0, 0);
}
int
sys_pkt_try_send(void *buf, size_t len)
{
return syscall(SYS_pkt_try_send, 1, (uint32_t)buf, (uint32_t)len, 0, 0, 0);
}
int
sys_pkt_try_receive(void *rev_buf, size_t *len)
{
// return 0;
return syscall(SYS_pkt_try_recv, 1, (uint32_t)rev_buf, (uint32_t)len, 0, 0, 0);
}

View File

@@ -0,0 +1,517 @@
/* See COPYRIGHT for copyright information. */
#include <inc/x86.h>
#include <inc/error.h>
#include <inc/string.h>
#include <inc/assert.h>
#include <kern/env.h>
#include <kern/pmap.h>
#include <kern/trap.h>
#include <kern/syscall.h>
#include <kern/console.h>
#include <kern/sched.h>
#include <kern/time.h>
#include <kern/e1000.h>
// Print a string to the system console.
// The string is exactly 'len' characters long.
// Destroys the environment on memory errors.
static void
sys_cputs(const char *s, size_t len)
{
// Check that the user has permission to read memory [s, s+len).
// Destroy the environment if not.
// LAB 3: Your code here.
user_mem_assert(curenv, (const void *) s, len, 0);
// Print the string supplied by the user.
cprintf("%.*s", len, s);
}
// Read a character from the system console without blocking.
// Returns the character, or 0 if there is no input waiting.
static int
sys_cgetc(void)
{
return cons_getc();
}
// Returns the current environment's envid.
static envid_t
sys_getenvid(void)
{
return curenv->env_id;
}
// Destroy a given environment (possibly the currently running environment).
//
// Returns 0 on success, < 0 on error. Errors are:
// -E_BAD_ENV if environment envid doesn't currently exist,
// or the caller doesn't have permission to change envid.
static int
sys_env_destroy(envid_t envid)
{
int r;
struct Env *e;
if ((r = envid2env(envid, &e, 1)) < 0)
return r;
if (e == curenv)
cprintf("[%08x] exiting gracefully\n", curenv->env_id);
else
cprintf("[%08x] destroying %08x\n", curenv->env_id, e->env_id);
env_destroy(e);
return 0;
}
// Deschedule current environment and pick a different one to run.
static void
sys_yield(void)
{
sched_yield();
}
// Allocate a new environment.
// Returns envid of new environment, or < 0 on error. Errors are:
// -E_NO_FREE_ENV if no free environment is available.
// -E_NO_MEM on memory exhaustion.
static envid_t
sys_exofork(void)
{
// Create the new environment with env_alloc(), from kern/env.c.
// It should be left as env_alloc created it, except that
// status is set to ENV_NOT_RUNNABLE, and the register set is copied
// from the current environment -- but tweaked so sys_exofork
// will appear to return 0.
// LAB 4: Your code here.
struct Env *newenv;
int32_t ret;
if ((ret = env_alloc(&newenv, sys_getenvid())) < 0) {
// 两个函数的返回值是一样的
return ret;
}
newenv->env_status = ENV_NOT_RUNNABLE;
newenv->env_tf = curenv->env_tf;
// newenv的返回值为0, 实现子进程返回0值
newenv->env_tf.tf_regs.reg_eax = 0;
// 返回值存放在eax中
return newenv->env_id;
// panic("sys_exofork not implemented");
}
// Set envid's env_status to status, which must be ENV_RUNNABLE
// or ENV_NOT_RUNNABLE.
//
// Returns 0 on success, < 0 on error. Errors are:
// -E_BAD_ENV if environment envid doesn't currently exist,
// or the caller doesn't have permission to change envid.
// -E_INVAL if status is not a valid status for an environment.
static int
sys_env_set_status(envid_t envid, int status)
{
// Hint: Use the 'envid2env' function from kern/env.c to translate an
// envid to a struct Env.
// You should set envid2env's third argument to 1, which will
// check whether the current environment has permission to set
// envid's status.
// LAB 4: Your code here.
struct Env *e;
if (envid2env(envid, &e, 1)) return -E_BAD_ENV;
if (status != ENV_NOT_RUNNABLE && status != ENV_RUNNABLE)
return -E_INVAL;
e->env_status = status;
return 0;
}
// Set envid's trap frame to 'tf'.
// tf is modified to make sure that user environments always run at code
// protection level 3 (CPL 3), interrupts enabled, and IOPL of 0.
//
// Returns 0 on success, < 0 on error. Errors are:
// -E_BAD_ENV if environment envid doesn't currently exist,
// or the caller doesn't have permission to change envid.
static int
sys_env_set_trapframe(envid_t envid, struct Trapframe *tf)
{
// LAB 5: Your code here.
// Remember to check whether the user has supplied us with a good
// address!
struct Env *env;
int r;
if ( (r = envid2env(envid, &env, 1)) < 0)
return r;
// 什么时候会出现没有权限访问的问题?
user_mem_assert(env, tf, sizeof(struct Trapframe), PTE_U);
// 直接整个结构体也是可以赋值的
// tf->tf_cs |= (GD_UT | 0x3);
tf->tf_eflags |= FL_IF;
// 普通进程无I/O权限
tf->tf_eflags &= ~FL_IOPL_MASK;
env->env_tf = *tf;
return 0;
}
// Set the page fault upcall for 'envid' by modifying the corresponding struct
// Env's 'env_pgfault_upcall' field. When 'envid' causes a page fault, the
// kernel will push a fault record onto the exception stack, then branch to
// 'func'.
//
// Returns 0 on success, < 0 on error. Errors are:
// -E_BAD_ENV if environment envid doesn't currently exist,
// or the caller doesn't have permission to change envid.
static int
sys_env_set_pgfault_upcall(envid_t envid, void *func)
{
// LAB 4: Your code here.
struct Env *e;
if (envid2env(envid, &e, 1))
return -E_BAD_ENV;
// cprintf("set pgfault upcall\n");
e->env_pgfault_upcall = func;
return 0;
// panic("sys_env_set_pgfault_upcall not implemented");
}
// Allocate a page of memory and map it at 'va' with permission
// 'perm' in the address space of 'envid'.
// The page's contents are set to 0.
// If a page is already mapped at 'va', that page is unmapped as a
// side effect.
//
// perm -- PTE_U | PTE_P must be set, PTE_AVAIL | PTE_W may or may not be set,
// but no other bits may be set. See PTE_SYSCALL in inc/mmu.h.
//
// Return 0 on success, < 0 on error. Errors are:
// -E_BAD_ENV if environment envid doesn't currently exist,
// or the caller doesn't have permission to change envid.
// -E_INVAL if va >= UTOP, or va is not page-aligned.
// -E_INVAL if perm is inappropriate (see above).
// -E_NO_MEM if there's no memory to allocate the new page,
// or to allocate any necessary page tables.
static int
sys_page_alloc(envid_t envid, void *va, int perm)
{
// Hint: This function is a wrapper around page_alloc() and
// page_insert() from kern/pmap.c.
// Most of the new code you write should be to check the
// parameters for correctness.
// If page_insert() fails, remember to free the page you
// allocated!
// LAB 4: Your code here.
int ret = 0;
struct Env *env;
if ((ret = envid2env(envid, &env, 1)) < 0)
return -E_BAD_ENV;
if((uintptr_t)va >= UTOP || PGOFF(va))
return -E_INVAL;
if ((perm & PTE_U) == 0 || (perm & PTE_P) == 0)
return -E_INVAL;
if (perm & ~PTE_SYSCALL)
return -E_INVAL;
struct PageInfo *pp = page_alloc(ALLOC_ZERO);
if(!pp)
return -E_NO_MEM;
if (page_insert(env->env_pgdir, pp, va, perm) < 0)
return -E_NO_MEM;
return 0;
// panic("sys_page_alloc not implemented");
}
// Map the page of memory at 'srcva' in srcenvid's address space
// at 'dstva' in dstenvid's address space with permission 'perm'.
// Perm has the same restrictions as in sys_page_alloc, except
// that it also must not grant write access to a read-only
// page.
//
// Return 0 on success, < 0 on error. Errors are:
// -E_BAD_ENV if srcenvid and/or dstenvid doesn't currently exist,
// or the caller doesn't have permission to change one of them.
// -E_INVAL if srcva >= UTOP or srcva is not page-aligned,
// or dstva >= UTOP or dstva is not page-aligned.
// -E_INVAL is srcva is not mapped in srcenvid's address space.
// -E_INVAL if perm is inappropriate (see sys_page_alloc).
// -E_INVAL if (perm & PTE_W), but srcva is read-only in srcenvid's
// address space.
// -E_NO_MEM if there's no memory to allocate any necessary page tables.
static int
sys_page_map(envid_t srcenvid, void *srcva,
envid_t dstenvid, void *dstva, int perm)
{
// Hint: This function is a wrapper around page_lookup() and
// page_insert() from kern/pmap.c.
// Again, most of the new code you write should be to check the
// parameters for correctness.
// Use the third argument to page_lookup() to
// check the current permissions on the page.
// LAB 4: Your code here.
int ret = 0;
struct Env *srcenv, *dstenv;
struct PageInfo *srcpp, *dstpp;
pte_t *pte;
if ((envid2env(srcenvid, &srcenv, 1) < 0 )|| ( envid2env(dstenvid, &dstenv, 1) < 0))
return -E_BAD_ENV;
if ((uintptr_t)srcva >= UTOP || PGOFF(srcva) || (uintptr_t)dstva >= UTOP || PGOFF(dstva))
return -E_INVAL;
if ( (perm & PTE_U) == 0 || (perm & PTE_P) == 0 || (perm & ~PTE_SYSCALL))
return -E_INVAL;
if (!(srcpp = page_lookup(srcenv->env_pgdir, srcva, &pte)))
return -E_INVAL;
if ((perm & PTE_W) && ((*pte & PTE_W) == 0))
return -E_INVAL;
if (page_insert(dstenv->env_pgdir, srcpp, dstva, perm) < 0)
return -E_NO_MEM;
return 0;
// panic("sys_page_map not implemented");
}
// Unmap the page of memory at 'va' in the address space of 'envid'.
// If no page is mapped, the function silently succeeds.
//
// Return 0 on success, < 0 on error. Errors are:
// -E_BAD_ENV if environment envid doesn't currently exist,
// or the caller doesn't have permission to change envid.
// -E_INVAL if va >= UTOP, or va is not page-aligned.
static int
sys_page_unmap(envid_t envid, void *va)
{
// Hint: This function is a wrapper around page_remove().
// LAB 4: Your code here.
int ret = 0;
struct Env *env;
if ((ret = envid2env(envid, &env, 1)) < 0)
return -E_BAD_ENV;
if ((uintptr_t)va >= UTOP || PGOFF(va))
return -E_INVAL;
page_remove(env->env_pgdir, va);
return 0;
// panic("sys_page_unmap not implemented");
}
// Try to send 'value' to the target env 'envid'.
// If srcva < UTOP, then also send page currently mapped at 'srcva',
// so that receiver gets a duplicate mapping of the same page.
//
// The send fails with a return value of -E_IPC_NOT_RECV if the
// target is not blocked, waiting for an IPC.
//
// The send also can fail for the other reasons listed below.
//
// Otherwise, the send succeeds, and the target's ipc fields are
// updated as follows:
// env_ipc_recving is set to 0 to block future sends;
// env_ipc_from is set to the sending envid;
// env_ipc_value is set to the 'value' parameter;
// env_ipc_perm is set to 'perm' if a page was transferred, 0 otherwise.
// The target environment is marked runnable again, returning 0
// from the paused sys_ipc_recv system call. (Hint: does the
// sys_ipc_recv function ever actually return?)
//
// If the sender wants to send a page but the receiver isn't asking for one,
// then no page mapping is transferred, but no error occurs.
// The ipc only happens when no errors occur.
//
// Returns 0 on success, < 0 on error.
// Errors are:
// -E_BAD_ENV if environment envid doesn't currently exist.
// (No need to check permissions.)
// -E_IPC_NOT_RECV if envid is not currently blocked in sys_ipc_recv,
// or another environment managed to send first.
// -E_INVAL if srcva < UTOP but srcva is not page-aligned.
// -E_INVAL if srcva < UTOP and perm is inappropriate
// (see sys_page_alloc).
// -E_INVAL if srcva < UTOP but srcva is not mapped in the caller's
// address space.
// -E_INVAL if (perm & PTE_W), but srcva is read-only in the
// current environment's address space.
// -E_NO_MEM if there's not enough memory to map srcva in envid's
// address space.
static int
sys_ipc_try_send(envid_t envid, uint32_t value, void *srcva, unsigned perm)
{
// LAB 4: Your code here.
struct Env *dstenv;
pte_t *pte;
struct PageInfo *pp;
int r;
if ( (r = envid2env( envid, &dstenv, 0)) < 0)
return r;
// 不处于等待接收状态, 或有进程已经请求发送数据
if ( (dstenv->env_ipc_recving != true) || dstenv->env_ipc_from != 0)
return -E_IPC_NOT_RECV;
if ((uint32_t)srcva < UTOP) {
if ( PGOFF(srcva))
return -E_INVAL;
if ( !(perm & PTE_P ) || !(perm & PTE_U) )
return -E_INVAL;
if (perm & (~ PTE_SYSCALL))
return -E_INVAL;
if ((pp = page_lookup(curenv->env_pgdir, srcva, &pte)) == NULL )
return -E_INVAL;
if ((perm & PTE_W) && !(*pte & PTE_W) )
return -E_INVAL;
// 接收进程愿意接收一个页
if (dstenv->env_ipc_dstva) {
// 开始映射
if( (r = page_insert(dstenv->env_pgdir, pp, dstenv->env_ipc_dstva, perm)) < 0)
return r;
dstenv->env_ipc_perm = perm;
}
}
dstenv->env_ipc_from = curenv->env_id;
dstenv->env_ipc_recving = false;
dstenv->env_ipc_value = value;
dstenv->env_status = ENV_RUNNABLE;
// 返回值
dstenv->env_tf.tf_regs.reg_eax = 0;
return 0;
//panic("sys_ipc_try_send not implemented");
}
// Block until a value is ready. Record that you want to receive
// using the env_ipc_recving and env_ipc_dstva fields of struct Env,
// mark yourself not runnable, and then give up the CPU.
//
// If 'dstva' is < UTOP, then you are willing to receive a page of data.
// 'dstva' is the virtual address at which the sent page should be mapped.
//
// This function only returns on error, but the system call will eventually
// return 0 on success.
// Return < 0 on error. Errors are:
// -E_INVAL if dstva < UTOP but dstva is not page-aligned.
static int
sys_ipc_recv(void *dstva)
{
// LAB 4: Your code here.
if ((uint32_t) dstva < UTOP ) {
if (PGOFF(dstva))
return -E_INVAL;
}
// 大于小于都可以赋值为desva。
curenv->env_ipc_dstva = dstva;
curenv->env_status = ENV_NOT_RUNNABLE;
curenv->env_ipc_recving = true;
curenv->env_ipc_from = 0;
sched_yield();
// panic("sys_ipc_recv not implemented");
return 0;
}
// Return the current time.
static int
sys_time_msec(void)
{
// LAB 6: Your code here.
return time_msec();
// panic("sys_time_msec not implemented");
}
int
sys_pkt_try_send(void * buf, size_t len)
{
user_mem_assert(curenv, buf, len, PTE_U);
return e1000_transmit(buf, len);
}
int
sys_pkt_try_receive(void *rev_buf, size_t *len)
{
return e1000_receive(rev_buf, len);
}
// Dispatches to the correct kernel function, passing the arguments.
int32_t
syscall(uint32_t syscallno, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5)
{
// Call the function corresponding to the 'syscallno' parameter.
// Return any appropriate return value.
// LAB 3: Your code here.
switch (syscallno) {
case SYS_cputs:
sys_cputs((const char*)a1, a2);
break;
case SYS_cgetc:
return sys_cgetc();
case SYS_getenvid:
return sys_getenvid();
case SYS_env_destroy:
return sys_env_destroy(a1);
case SYS_yield:
sys_yield();
break;
case SYS_page_alloc:
return sys_page_alloc((envid_t)a1, (void * )a2, (int )a3);
case SYS_env_set_pgfault_upcall:
return sys_env_set_pgfault_upcall((envid_t) a1, (void *) a2);
case SYS_page_map:
return sys_page_map((envid_t) a1, (void *) a2, (envid_t) a3, (void *) a4, (int) a5);
case SYS_page_unmap:
return sys_page_unmap((envid_t) a1, (void *) a2);
case SYS_exofork:
return sys_exofork();
case SYS_env_set_status:
return sys_env_set_status((envid_t) a1, (int) a2);
case SYS_ipc_recv:
return sys_ipc_recv( (void *) a1);
case SYS_ipc_try_send:
return sys_ipc_try_send((envid_t) a1, (uint32_t) a2, (void *) a3, (int) a4);
case SYS_env_set_trapframe:
return sys_env_set_trapframe((envid_t) a1, (struct Trapframe *) a2);
case SYS_time_msec:
return sys_time_msec();
case SYS_pkt_try_send:
return sys_pkt_try_send((void *) a1, (size_t) a2);
case SYS_pkt_try_recv:
return sys_pkt_try_receive((void *) a1, (size_t *) a2);
case NSYSCALLS:
return -E_INVAL;
default:
return -E_INVAL;
}
return 0;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More