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

📄 main.c

📁 WinAoE is an open source GPLv3 driver for using AoE (ATA over Ethernet) on Microsoft Windows
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
  Copyright 2006-2008, V.
  For contact information, see http://winaoe.org/

  This file is part of WinAoE.

  WinAoE is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  WinAoE is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with WinAoE.  If not, see <http://www.gnu.org/licenses/>.
*/

asm(".code16gcc\n");
#include "main.h"
#include "asm.h"
#include "pxe.h"
#include "lib.h"

#define D(x) printf(#x "\n");
#define BP 562

int imagesize = (int)&end;

unsigned char clientmac[6];
unsigned char servermac[6];
unsigned int major;
unsigned int minor;
int tag = 0;

int heads, sectors, cylinders;
unsigned int disksize;
unsigned int realdisksize;

unsigned char bootdrive;
unsigned char aoedrive;
int drives = 0;
t_abft _abft;
t_abft *abft;
int checksum = 0;

int getbootinfo();
void getbootdriveinfo();
void readwrite(unsigned char read, unsigned int lba, int count, unsigned short seg, unsigned short off);
int pollisr();
void sendreceive(t_aoe* sendbuffer, int sendsize, t_aoe* receivebuffer, int* receivesize);
void sendpacket(void* packet, int size);
int processpacket(void* buffer, int* size);
void printbuffer(unsigned short seg, unsigned short off, size_t n);

int chk() {
  int i1, i2, r = 0;
  unsigned char buffer[16];
  for (i1 = 0x9ecc; i1 < 0xa000; i1++) {
//  for (i1 = (segment + 0x1000); i1 < 0x9c7f; i1++) {
    segmemcpy((segment << 16) + (int)buffer, i1 << 16, 16);
    for (i2 = 0; i2 < 16; i2++) {
      r += buffer[i2];
    }
  }
  return r;
}

int _main(t_cpu *cpu) {
  t_PXENV_UNDI_OPEN undiopen;
  t_PXENV_UNDI_GET_INFORMATION undigetinformation;
  int i, c, v;
  unsigned char k;

  printf("\nWelcome to AoE Boot...\n\n");

  checksum = chk();
  printf("Checksum: %08x\n", checksum);

  memset(servermac, 0xff, 6);
  if (!(v = pxeinit())) {
    printf("PXE API Vector not found\n");
    halt();
  }

  memset((void*)&undiopen, 0, sizeof(undiopen));
  undiopen.PktFilter = FLTR_DIRECTED | 0xf;
  if (api(PXENV_UNDI_OPEN, &undiopen)) apierror("PXENV_UNDI_OPEN", undiopen.Status);
  memset((void*)&undigetinformation, 0, sizeof(undigetinformation));
  if (api(PXENV_UNDI_GET_INFORMATION, &undigetinformation)) apierror("PXENV_UNDI_GET_INFORMATION", undigetinformation.Status);
  irq = undigetinformation.IntNumber;
  if (!getbootinfo()) halt();
  printf("Segment: %04x  API: %04x:%04x  IRQ: %d%s  NIC: %02x:%02x:%02x:%02x:%02x:%02x\n", segment, ((v >> 16) & 0xffff), (v & 0xffff), irq, (irq == 0?" (polling)":""), clientmac[0], clientmac[1], clientmac[2], clientmac[3], clientmac[4], clientmac[5]);

  getbootdriveinfo();
  segmemcpy(((segment << 16) + (int)&drives), 0x00400075, 1);
  printf("Target: e%d.%d  Size: %dM  Cylinders: %d  Heads: %d  Sectors: %d\n\n", major, minor, ((disksize / 2) / 1024), cylinders, heads, sectors);
  do {
    printf("Boot from (N)etwork");
    if (drives > 0) printf(", (H)arddisk");
    printf(" or (F)loppy? ");
    if ((k = getkey(PROMPTTIMEOUT)) >= 'a') k -= 'a' - 'A';
    if (k == '\0' || k == '\n') {
      k = 'N';
    } else {
      putchar(k);
    }
    putchar('\n');
  } while (!(k == 'N' || k == 'F' || (k == 'H' && drives > 0)));

  switch (k) {
    case 'N':
      abft = (t_abft *)((((int)&_abft) + 15) & 0xfffffff0);
      memset(abft, 0, sizeof(t_abft) - 15);
      abft->signature = 0x54464261;
      abft->length = sizeof(t_abft) - 15;
      abft->revision = 1;
      memcpy(abft->clientmac, clientmac, 6);
      abft->major = major;
      abft->minor = minor;
      c = 0;
      for (i = 0; i < (sizeof(t_abft) - 15); i++) c -= ((unsigned char *)abft)[i];
      abft->checksum = c & 0xff;
      bootdrive = 0x80;
      aoedrive = 0x80;
      drives++;
      break;
    case 'H':
      bootdrive = 0x80;
      aoedrive = 0x80 + drives++;
      break;
    case 'F':
      bootdrive = 0x00;
      aoedrive = 0x80 + drives++;
      break;
  }

  segmemcpy(0x00400075, (((segment << 16) + (int)&drives)), 1);
  cpu->eax &= 0xffff0000;
  cpu->eax |= 0x0201;
  cpu->ecx &= 0xffff0000;
  cpu->ecx |= 0x0001;
  cpu->ebx &= 0xffff0000;
  cpu->ebx |= 0x7c00;
  cpu->edx &= 0xffff0000;
  cpu->edx |= bootdrive;
  cpu->es &= 0;
  oldint13 = GETVECTOR(0x13);
  SETVECTOR(0x13, (segment << 16) + (int)int13);
  return 0;
}

int getbootinfo() {
  t_PXENV_GET_CACHED_INFO getinfo;
  BOOTPLAYER info;
  char rootpath[64];
  char *endptr;
  int i, l, e;

  memset((void *)&getinfo, 0, sizeof(getinfo));
  memset((void *)&info, 0, sizeof(info));
  getinfo.PacketType = PXENV_PACKET_TYPE_CACHED_REPLY;
  getinfo.BufferSize = 0;
  getinfo.Buffer.segment = 0;
  getinfo.Buffer.offset = 0;
  if (api(PXENV_GET_CACHED_INFO, (void *)&getinfo)) apierror("PXENV_GET_CACHED_INFO", getinfo.Status);
  segmemcpy(((segment << 16) + (int)&info), ((getinfo.Buffer.segment << 16) + getinfo.Buffer.offset), sizeof(info));
  memcpy(clientmac, info.CAddr, 6);

  if ((*(unsigned int*)info.vendor.v.magic) != VM_RFC1048) {
    printf("Invalid DHCP options magic...\n");
    return 0;
  }

  i = 4;
  while (i < BOOTP_DHCPVEND && info.vendor.d[i] != 0xff) {
    if (info.vendor.d[i] == 0x11) break;
    i++;
    i += info.vendor.d[i];
    i++;
  }
  if (i >= BOOTP_DHCPVEND || info.vendor.d[i] == 0xff) {
    printf("No root-path found in DHCP options...\n");
    return 0;
  }

  i++;
  if (info.vendor.d[i] + i >= BOOTP_DHCPVEND) {
    printf("DHCP option block > BOOTP_DHCPVEND bytes, root-path truncated...\n");
    return 0;
  }

  l = info.vendor.d[i];
  memcpy(&rootpath[0], &info.vendor.d[i + 1], l);
  rootpath[l] = '\0';
  i = 0;

  while (i < l && rootpath[i] == ' ') i++;
  e = 1;
  do {
    if (tolower(rootpath[i++]) != 'a') break;
    if (tolower(rootpath[i++]) != 'o') break;
    if (tolower(rootpath[i++]) != 'e') break;
    if (rootpath[i++] != ':') break;
    if (tolower(rootpath[i++]) != 'e') break;
    if (!isdigit(rootpath[i])) break;
    major = strtol(&rootpath[i], &endptr, 10);
    i += endptr - &rootpath[i];
    if (rootpath[i++] != '.') break;
    if (!isdigit(rootpath[i])) break;
    minor = strtol(&rootpath[i], &endptr, 10);
    i += endptr - &rootpath[i];
    e = 0;
  } while (0);

  if (e) {
    printf("Error in root-path\n");
    return 0;
  }

  if (major > 65535) {
    printf("Error in major...\n");
    return 0;
  }

  if (major > 255) {
    printf("Error in minor...\n");
    return 0;
  }

  while (i < l && (rootpath[i] == ' ' || rootpath[i] == '\0')) i++;
  if (i != l) {
    printf("Garbage after minor...");
    return 0;
  }
  return 1;
}

void getbootdriveinfo() {
  unsigned char sendbuffer[MAXPACKETSIZE];
  unsigned char receivebuffer[MAXPACKETSIZE];
  t_aoe* send = (t_aoe*)sendbuffer;
  t_aoe* receive = (t_aoe*)receivebuffer;
  t_mbr* mbr;
  int i;

  memset(send, 0, sizeof(t_aoe));
  memcpy(send->dst, servermac, 6);
  memcpy(send->src, clientmac, 6);
  send->protocol = htons(AOE_PROTOCOL);
  send->ver = AOE_VERSION;
  send->major = htons(major);
  send->minor = minor;
  send->command = 0;
  send->aflags = 0;
  send->count = 1;

  send->cmd = 0xec;			// IDENTIFY DEVICE
  sendreceive(send, sizeof(t_aoe) - (2 * SECTORSIZE), receive, &i);
  realdisksize = disksize = *(unsigned int*)&(receive->data[200]);

  send->cmd = 0x24;			// READ SECTOR
  send->lba0 = 0;
  send->lba1 = 0;
  send->lba2 = 0;
  send->lba3 = 0;
  send->lba4 = 0;
  send->lba5 = 0;
  sendreceive(send, sizeof(t_aoe) - (2 * SECTORSIZE), receive, &i);
  mbr = (t_mbr*)&(receive->data[0]);

  heads = 255;
  sectors = 63;
  if (mbr->magic == 0xaa55) {
    for (i = 0; i < 4; i++) {
      if (mbr->partition[i].size != 0) {
        heads = mbr->partition[i].endhead + 1;
        sectors = mbr->partition[i].endsector;
        break;
      }
    }
  }
  cylinders = disksize / (heads * sectors);
  disksize = cylinders * heads * sectors;
}

void _int13(t_cpu *cpu) {
  t_INT13_EXTENDED_READWRITE rwpacket;
  t_INT13_EXTENDED_GET_PARAMETERS parameterspacket;
  unsigned int cylinder, head, sector, lba;
  int c;

  if (checksum != (c = chk())) {
    printf("\n\nin checksum failed on tag: %d (%08x != %08x)\n", tag, checksum, c);
    debug();
    halt();
  }
  switch ((cpu->eax >> 8) & 0xff) {
    // reset disk
    //  dl: drive number
    // returns:
    //  ah = 0 and clear cf on success
    case 0x00:
      if ((cpu->edx & 0xff) != aoedrive) goto unhandled;
      cpu->eax &= ~(0xff << 8);
      cpu->eflags &= ~1;
      break;

    // read sectors & write sectors
    //  al: number of sectors to read/write (must be nonzero)
    //  ch: low eight bits of cylinder number
    //  cl: sector number 1-63 (bits 0-5)
    //      high two bits of cylinder (bits 6-7)
    //  dh: head number
    //  dl: drive number
    //  es:bx: data buffer
    // returns:
    //  ah = 0 and clear cf on success
    case 0x02:
    case 0x03:
      if ((cpu->edx & 0xff) != aoedrive) goto unhandled;
      cylinder = ((cpu->ecx >> 8) & 0xff) + ((cpu->ecx & 0xc0) << 2);
      head = (cpu->edx >> 8) & 0xff;
      sector = cpu->ecx & 0x3f;
      lba = (((cylinder * heads) + head) * sectors) + sector - 1;
      readwrite((((cpu->eax >> 8) & 0xff) == 0x02?1:0), lba, cpu->eax & 0xff, cpu->es, cpu->ebx & 0xffff);
      cpu->eax &= ~(0xff << 8);
      cpu->eflags &= ~1;
      break;

    // verify sectors
    //  dl: drive number
    // returns:
    //  ah = 0 and clear cf on success
    case 0x04:
      if ((cpu->edx & 0xff) != aoedrive) goto unhandled;
      cpu->eax &= ~(0xff << 8);
      cpu->eflags &= ~1;
      break;

    // get parameters
    //  dl: drive number
    // returns:
    //  ah = 0 and clear cf on success
    //  ch: low eight bits of maximum cylinder number
    //  cl: maximum sector number (bits 5-0)
    //      high two bits of maximum cylinder number (bits 7-6)
    //  dh: maximum head number
    //  dl: number of drives
    case 0x08:
      if ((cpu->edx & 0xff) != aoedrive) goto unhandled;
      cpu->ecx &= ~0xffff;
      if (cylinders > 1024) {
        cpu->ecx |= 0x3ff << 6;
      } else {
        cpu->ecx |= ((cylinders - 1) & 0xff) << 8;
        cpu->ecx |= ((cylinders - 1) >> 8) << 6;
      }
      cpu->ecx |= sectors;

      cpu->edx &= ~0xffff;
      cpu->edx |= (heads - 1) << 8;
      cpu->edx |= drives;

      cpu->eax &= ~(0xff << 8);
      cpu->eflags &= ~1;
      break;

    // get disk type
    //  dl: drive number
    // returns:
    //  clear cf on success
    //  ah: type (3 = harddisk)
    //  cx:dx: number of sectors
    case 0x15:
      if ((cpu->edx & 0xff) != aoedrive) goto unhandled;
      if ((cpu->edx & 0xff) != aoedrive) {
        cpu->eflags |= 1;
        break;
      }
      cpu->eax &= ~(0xff << 8);

⌨️ 快捷键说明

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