
// HAUKI_MODULE: BCMINIT
// HAUKI_MODULE: BCMSEND
// HAUKI_MODULE: BCMRECV

#include "../hauki.h"

#define BROADCOM_VENDOR 0x14E4

// Broadcom Tigon3 MMIO Offsets
#define TG3_MAC_ADDR_HIGH      0x0410
#define TG3_MAC_ADDR_LOW       0x0414
#define TG3_SEND_MAILBOX       0x0300 // TX BD Producer Index
#define TG3_RECV_MAILBOX       0x0200 // RX BD Return Index

// Safe DMA Memory Regions
#define TX_RING_ADDR           0x220000
#define TX_BUFS_ADDR           0x230000
#define RX_RING_ADDR           0x240000
#define RX_BUFS_ADDR           0x250000
#define NUM_DESC               16

// Broadcom TX Buffer Descriptor (BD) Structure (16 bytes)
struct tg3_tx_desc {
unsigned int addr_high;
unsigned int addr_low;
unsigned short len;
unsigned short flags;
unsigned int vlan_tag; // Also used for opaque data
} attribute((packed));

// Broadcom RX Buffer Descriptor (BD) Structure (16 bytes)
struct tg3_rx_desc {
unsigned int addr_high;
unsigned int addr_low;
unsigned short len;
unsigned short idx_flags;
unsigned short type_flags;
unsigned short ip_tcp_csum;
unsigned int err_vlan;
} attribute((packed));

static unsigned int bcm_mmio_base = 0;
static struct tg3_tx_desc* tx_ring;
static unsigned char* tx_bufs;
static int tx_idx = 0;

static struct tg3_rx_desc* rx_ring;
static unsigned char* rx_bufs;
static int rx_idx = 0;

static unsigned char my_mac[6] = {0};

static unsigned int pci_read_bcm(unsigned char bus, unsigned char slot, unsigned char func, unsigned char offset) {
unsigned int address = (unsigned int)((bus << 16) | (slot << 11) | (func << 8) | (offset & 0xFC) | 0x80000000);
outl(0xCF8, address); return inl(0xCFC);
}

static void pci_write_bcm(unsigned char bus, unsigned char slot, unsigned char func, unsigned char offset, unsigned int data) {
unsigned int address = (unsigned int)((bus << 16) | (slot << 11) | (func << 8) | (offset & 0xFC) | 0x80000000);
outl(0xCF8, address); outl(0xCFC, data);
}

static inline void mmio_write32(unsigned int reg, unsigned int val) {
((volatile unsigned int)(bcm_mmio_base + reg)) = val;
}

static inline unsigned int mmio_read32(unsigned int reg) {
return ((volatile unsigned int)(bcm_mmio_base + reg));
}

void mod_BCMINIT(char* args) {
kprint("--- BROADCOM TIGON3 PHYSICAL INITIALIZATION ---\r\n");
int found = 0;

// Broadcom cards are sometimes pushed to higher buses on physical motherboards
for (int bus = 0; bus < 128; bus++) { // Extended scan for weird bridges
    for (int slot = 0; slot < 32; slot++) {
        unsigned int vendor_device = pci_read_bcm(bus, slot, 0, 0);
        if ((vendor_device & 0xFFFF) == BROADCOM_VENDOR) {
            found = 1;

            // 1. Enable Bus Mastering & Memory Space
            unsigned int cmd = pci_read_bcm(bus, slot, 0, 0x04);
            pci_write_bcm(bus, slot, 0, 0x04, cmd | 0x06);

            // 2. Lock MMIO Base
            bcm_mmio_base = pci_read_bcm(bus, slot, 0, 0x10) & 0xFFFFFFF0;
            kprint("[+] BCM MMIO Locked: 0x"); print_hex32(bcm_mmio_base); kprint("\r\n");

            // 3. Extract Physical MAC
            unsigned int mac_high = mmio_read32(TG3_MAC_ADDR_HIGH);
            unsigned int mac_low  = mmio_read32(TG3_MAC_ADDR_LOW);

            my_mac[0] = (mac_high >> 8) & 0xFF;
            my_mac[1] = mac_high & 0xFF;
            my_mac[2] = (mac_low >> 24) & 0xFF;
            my_mac[3] = (mac_low >> 16) & 0xFF;
            my_mac[4] = (mac_low >> 8) & 0xFF;
            my_mac[5] = mac_low & 0xFF;

            kprint("[+] Physical MAC Address: ");
            for(int i=0; i<6; i++) {
                char hex[] = "0123456789ABCDEF";
                char str[3] = { hex[(my_mac[i] >> 4) & 0xF], hex[my_mac[i] & 0xF], '\0' };
                kprint(str); if (i < 5) kprint(":");
            }
            kprint("\r\n");

            // 4. Map TX Descriptor Ring in RAM
            tx_ring = (struct tg3_tx_desc*)TX_RING_ADDR;
            tx_bufs = (unsigned char*)TX_BUFS_ADDR;
            for(int i=0; i<NUM_DESC; i++) {
                tx_ring[i].addr_high = 0; // 32-bit OS
                tx_ring[i].addr_low = (unsigned int)(tx_bufs + (i * 2048));
                tx_ring[i].len = 0;
                tx_ring[i].flags = 0;
                tx_ring[i].vlan_tag = 0;
            }
            tx_idx = 0;

            // 5. Map RX Descriptor Ring in RAM
            rx_ring = (struct tg3_rx_desc*)RX_RING_ADDR;
            rx_bufs = (unsigned char*)RX_BUFS_ADDR;
            for(int i=0; i<NUM_DESC; i++) {
                rx_ring[i].addr_high = 0;
                rx_ring[i].addr_low = (unsigned int)(rx_bufs + (i * 2048));
                rx_ring[i].len = 0;
                rx_ring[i].idx_flags = 0;
            }
            rx_idx = 0;

            kprint("[+] Tigon3 Mailbox DMA Rings Mapped in RAM.\r\n");
            return;
        }
    }
}
if (!found) kprint("[-] Broadcom silicon not found.\r\n");


}

void mod_BCMSEND(char* args) {
if (bcm_mmio_base == 0) { kprint("?RUN BCMINIT FIRST\r\n"); return; }
while (*args == ' ' || *args == '"') args++;

unsigned char* buf = tx_bufs + (tx_idx * 2048);

// 1. Clean the buffer to remove the "Ghost in the RAM" garbage!
for(int i=0; i<2048; i++) buf[i] = 0;

// 2. Build Ethernet Header
for(int i=0; i<6; i++) buf[i] = 0xFF; // Broadcast MAC
for(int i=0; i<6; i++) buf[6+i] = my_mac[i]; // Source Physical MAC
buf[12] = 0x88; buf[13] = 0xB5; // Custom Bare Metal EtherType

// 3. Copy Payload
int payload_len = 0;
while(args[payload_len] && args[payload_len] != '"' && payload_len < 1500) {
    buf[14 + payload_len] = args[payload_len];
    payload_len++;
}

int total_len = 14 + payload_len;
if (total_len < 60) total_len = 60; // Min Ethernet frame size

// 4. Configure Broadcom TX Buffer Descriptor
tx_ring[tx_idx].len = total_len;
// Packet End Flag (0x0004) tells the ASIC this BD is the end of the frame
tx_ring[tx_idx].flags = 0x0004;

// 5. Strike the Send Mailbox!
tx_idx = (tx_idx + 1) % NUM_DESC;
mmio_write32(TG3_SEND_MAILBOX, tx_idx);

kprint("[+] Payload dropped in TX Mailbox. ASIC Notified.\r\n");


}

void mod_BCMRECV(char* args) {
kprint("BCMRECV: Pending physical hardware validation.\r\n");
}