Hi,
david wrote:i do a test.
1. hook int 19h
2. call int 1Ah(call it in my own int 19h interrupt routine)
but, CF=1, bx=0...
in all, failed.
so , i guess BIOS doesn't load Onboard NIC driver since Power On.
Let's start from the start, just to make sure you've got the right idea....
Step 1: Write some testing code like this:
Code: Select all
ORG 0x7C00
BITS 16
START:
mov ax,0xB800 ;ax = segment for video display memory (text mode assumed)
mov ds,ax ;ax = segment for video display memory
mov dword [0],0x12345678 ;Trash the top left 2 characters on the screen
.die:
jmp .die ;Lock up
Step 2: Assemble this code, and copy the binary into your TFTP server's directory. For me this directory is "/tftproot", so I'd end up with (for e.g.) the file "/tftproot/bootpxe.bin".
Step 3: Setup your DHCP server so that it tells remote clients to download the file "bootpxe.bin" from the TFTP server. For an example, I'm using Gentoo Linux and my "/etc/dhcp/dhcpd.conf" file looks like this:
Code: Select all
authoritative;
# Use this to send dhcp log messages to a different log file (you also
# have to hack syslog.conf to complete the redirection).
log-facility local7;
# DHCP configuration file for DHCP ISC 3.0
ddns-update-style none;
default-lease-time 86400;
max-lease-time 86400;
deny unknown-clients;
# Definition of PXE-specific options
# Code 1: Multicast IP address of boot file server
# Code 2: UDP port that client should monitor for MTFTP responses
# Code 3: UDP port that MTFTP servers are using to listen for MTFTP requests
# Code 4: Number of seconds a client must listen for activity before trying
# to start a new MTFTP transfer
# Code 5: Number of seconds a client must listen before trying to restart
# a MTFTP transfer
option space PXE;
option PXE.mtftp-ip code 1 = ip-address;
option PXE.mtftp-cport code 2 = unsigned integer 16;
option PXE.mtftp-sport code 3 = unsigned integer 16;
option PXE.mtftp-tmout code 4 = unsigned integer 8;
option PXE.mtftp-delay code 5 = unsigned integer 8;
option PXE.discovery-control code 6 = unsigned integer 8;
option PXE.discovery-mcast-addr code 7 = ip-address;
next-server 10.0.0.2;
subnet 10.0.0.0 netmask 255.255.255.0 {
class "pxeclients" {
match if substring (option vendor-class-identifier, 0, 9) = "PXEClient";
option vendor-class-identifier "PXEClient";
vendor-option-space PXE;
# At least one of the vendor-specific PXE options must be set in
# order for the client boot ROMs to realize that we are a PXE-compliant
# server. We set the MCAST IP address to 0.0.0.0 to tell the boot ROM
# that we can't provide multicast TFTP (address 0.0.0.0 means no
# address).
option PXE.mtftp-ip 0.0.0.0;
# This is the name of the file the boot ROMs should download.
filename "/bootpxe.bin";
}
host test1 {
# Use your slave's MAC address
hardware ethernet 00:0F:EA:C4:B8:45;
# Give your slave a static IP
fixed-address 10.0.0.3;
server-name "master";
# Use your gateway IP, if required
#option routers 10.0.0.138;
# Use your DNS IP, if required
#option domain-name-servers 10.0.0.138;
#option domain-name "mydomain.com";
# Use your slave hostname
#option host-name "test1";
# Etherboot and pxe boot with a mac specific image
#option root-path "/tftproot/10.0.0.3";
#option root-path "/tftproot";
if substring (option vendor-class-identifier, 0, 9) = "Etherboot" {
filename "/bootpxe.bin";
} else if substring (option vendor-class-identifier, 0,9) ="PXEClient" {
filename "/bootpxe.bin";
}
}
host test2 {
hardware ethernet 00:80:C8:E7:E7:FD;
fixed-address 10.0.0.8;
server-name "master";
if substring (option vendor-class-identifier, 0, 9) = "Etherboot" {
filename "/bootpxe.bin";
} else if substring (option vendor-class-identifier, 0,9) ="PXEClient" {
filename "/bootpxe.bin";
}
}
host test3 {
hardware ethernet 00:09:5B:1A:E8:C4;
fixed-address 10.0.0.9;
server-name "master";
if substring (option vendor-class-identifier, 0, 9) = "Etherboot" {
filename "/bootpxe.bin";
} else if substring (option vendor-class-identifier, 0,9) ="PXEClient" {
filename "/bootpxe.bin";
}
}
host test4 {
hardware ethernet 00:03:FF:21:D2:C3;
fixed-address 10.0.0.16;
server-name "master";
if substring (option vendor-class-identifier, 0, 9) = "Etherboot" {
filename "/bootpxe.bin";
} else if substring (option vendor-class-identifier, 0,9) ="PXEClient" {
filename "/bootpxe.bin";
}
}
}
There's probably a cleaner way to do this (e.g. one "generic client" entry rather than one entry for each client), but I'm lazy and it works for me..
Step 4: Configure the BIOS (or NIC ROM) on the client machine to boot from network, then (with the server running) boot the client.
Note: for step 4, a properly configured etherboot floppy (e.g. etherboot compiled as a boot floppy to suit your NIC) is a good alternative if the client's ROMs don't actually support booting from network.
If everything is right, the client should configure networking (using the DHCP server), download your boot loader from the TFTP server, then execute your boot loader. In this case the top left 2 characters on the screen will be trashed and the computer will lock up (because that's what the code above does).
Now, if you've got all of the above working, then...
From the PXE Specification ("3.1 PXE Installation Check"):
"
The primary users of these installation check methods are protocol drivers designed to use the PXE
APIs. NBPs do not need to use these installation check procedures because the address of the !PXE
structure is passed to them on the stack.
Note: For backward compatibility with existing applications, the address of the PXENV+ structure
must also be passed in the ES:BX register pair. Since support for the PXENV+ structure is not
planned for future versions, new applications (for example, universal protocol drivers) should be
written to !PXE."
The "NBP" is your Network Bootstrap Program (your bootloader) so no installation check is necessary, and the address of the !PXE structure is passed to your bootloader on the stack. For backward compatability with an older version of the PXE specification the address of the PXENV+ structure is also passed in ES:BX.
The !PXE structure is a newer structure that contains the segment and offset for the !PXE API. The PXENV+ structure is an older structure that contains the segment and offset for the PXENV+ API. This is 2 different structures with 2 different APIs. However, the different APIs are functionally equivelent - the only difference is the calling conventions.
Because of this I use a wrapper around the API itself, so that my boot loader will use the !PXE API calling conventions and !PXE entry point if !PXE was supported, and use PXENV+ calling conventions and PXENV+ entry point if !PXE isn't supported. This just means that I can call my wrapper and don't need to care if !PXE is supported or not (ie. my boot loader should work fine on newer NICs that comply with version 2.1 of the PXE specification and older NICs that only comply with older versions of the PXE specification).
My init code just tries to get the address of the !PXE and PXENV+ structures so that later code (in the file "bcos/80x86/sys_src/p1/bootpxe/_doc/main.html") can check if either of the structures were sane (and setup the API wrapper so that I can use it easily).
Cheers,
Brendan