4 * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #include <gpxe/device.h>
41 * @v data Data to checksum
42 * @v len Length of data
43 * @ret sum Byte checksum
45 static uint8_t checksum ( void *data, size_t len ) {
46 uint8_t *bytes = data;
56 * Unregister a PXE device
61 static void unregister_pxedev ( struct pxe_device *pxe ) {
63 list_del ( &pxe->dev.siblings );
64 DBGC ( pxe, "PXE %p unregistered\n", pxe );
67 static void pxebus_remove ( struct root_device *rootdev );
72 * @v rootdev PXE bus root device
74 * Scans the PXE bus for devices and registers all devices it can
77 static int pxebus_probe ( struct root_device *rootdev ) {
78 struct pxe_device *pxe = NULL;
86 /* Scan through allocated base memory for PXENV+ structure */
87 get_real ( fbms, BDA_SEG, BDA_FBMS );
88 for ( segment = ( fbms << 6 ) ; segment < 0xa000 ; segment++ ) {
90 /* Verify PXENV+ signature and checksum */
91 copy_from_real ( &pxenv, segment, 0, sizeof ( pxenv ) );
92 if ( memcmp ( pxenv.Signature, "PXENV+", 6 ) != 0 )
94 DBG ( "Found PXENV+ signature at %04x0\n", segment );
95 if ( checksum ( &pxenv, sizeof ( pxenv ) ) != 0 ) {
96 DBG ( "...bad checksum\n" );
100 /* Allocate PXE device structure */
101 pxe = malloc ( sizeof ( *pxe ) );
106 memset ( pxe, 0, sizeof ( *pxe ) );
108 /* Add to device hierarchy */
109 pxe->dev.parent = &rootdev->dev;
110 INIT_LIST_HEAD ( &pxe->dev.children );
111 list_add ( &pxe->dev.siblings, &rootdev->dev.children );
113 /* Populate PXE device structure */
114 undi_cs = pxenv.UNDICodeSeg;
115 pxe->pxenv.segment = undi_cs;
116 pxe->pxenv.offset = ( ( segment - undi_cs ) << 4 );
117 DBGC ( pxe, "PXE %p has PXENV+ structure at %04x:%04x\n",
118 pxe, pxe->pxenv.segment, pxe->pxenv.offset );
119 pxe->entry = pxenv.RMEntry;
120 if ( pxenv.Version >= 0x0201 ) {
121 pxe->ppxe = pxenv.PXEPtr;
122 copy_from_real ( &ppxe, pxe->ppxe.segment,
123 pxe->ppxe.offset, sizeof ( ppxe ) );
124 if ( ( memcmp ( ppxe.Signature, "!PXE", 4 ) == 0 ) &&
125 ( checksum ( &ppxe, sizeof ( ppxe ) ) == 0 ) ) {
126 DBGC ( pxe, "PXE %p has !PXE structure at "
128 pxe->ppxe.segment, pxe->ppxe.offset );
129 pxe->entry = ppxe.EntryPointSP;
132 DBGC ( pxe, "PXE %p using entry point at %04x:%04x\n", pxe,
133 pxe->entry.segment, pxe->entry.offset );
135 /* Register PXE device */
136 if ( undi_probe ( pxe ) == 0 ) {
137 /* Device registered; drop reference */
140 /* Not registered; re-use struct pxe_device */
141 list_del ( &pxe->dev.siblings );
150 pxebus_remove ( rootdev );
155 * Remove PXE root bus
157 * @v rootdev PXE bus root device
159 static void pxebus_remove ( struct root_device *rootdev ) {
160 struct pxe_device *pxe;
161 struct pxe_device *tmp;
163 list_for_each_entry_safe ( pxe, tmp, &rootdev->dev.children,
165 unregister_pxedev ( pxe );
170 /** PXE bus root device driver */
171 static struct root_driver pxe_root_driver = {
172 .probe = pxebus_probe,
173 .remove = pxebus_remove,
176 /** PXE bus root device */
177 struct root_device pxe_root_device __root_device = {
179 .driver = &pxe_root_driver,