📄 main.c
字号:
/*
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 + -