60 #define EINFO_EPXECALL \ 61 __einfo_uniqify ( EINFO_EPLATFORM, 0x01, \ 62 "External PXE API error" ) 63 #define EPXECALL( status ) EPLATFORM ( EINFO_EPXECALL, status ) 71 #define UNDI_HACK_EB54 0x0001 76 #define UNDI_INITIALIZE_RETRY_MAX 10 79 #define UNDI_INITIALIZE_RETRY_DELAY_MS 200 82 #define UNDI_RX_QUOTA 4 85 #define UNDI_RX_ALIGN 16 96 #define undinet_params __use_data16 ( undinet_params ) 105 #define undinet_entry_point __use_data16 ( undinet_entry_point ) 109 #define RDTSC_IF_PROFILING "rdtsc\n\t" 111 #define RDTSC_IF_PROFILING "" 116 { .
name =
"undinet.irq" };
120 { .
name =
"undinet.rx" };
136 { .
name =
"undinet.tx" },
137 { .name =
"undinet.tx_p2r" },
138 { .name =
"undinet.tx_ext" },
139 { .name =
"undinet.tx_r2p" },
149 { .
name =
"undinet.isr" },
150 { .name =
"undinet.isr_p2r" },
151 { .name =
"undinet.isr_ext" },
152 { .name =
"undinet.isr_r2p" },
161 { .
name =
"undinet.unknown" },
162 { .name =
"undinet.unknown_p2r" },
163 { .name =
"undinet.unknown_ext" },
164 { .name =
"undinet.unknown_r2p" },
169 { .
name =
"undinet.misc" },
170 { .name =
"undinet.misc_p2r" },
171 { .name =
"undinet.misc_ext" },
172 { .name =
"undinet.misc_r2p" },
190 switch (
function ) {
192 return "PXENV_START_UNDI";
194 return "PXENV_STOP_UNDI";
196 return "PXENV_UNDI_STARTUP";
198 return "PXENV_UNDI_CLEANUP";
200 return "PXENV_UNDI_INITIALIZE";
202 return "PXENV_UNDI_RESET_ADAPTER";
204 return "PXENV_UNDI_SHUTDOWN";
206 return "PXENV_UNDI_OPEN";
208 return "PXENV_UNDI_CLOSE";
210 return "PXENV_UNDI_TRANSMIT";
212 return "PXENV_UNDI_SET_MCAST_ADDRESS";
214 return "PXENV_UNDI_SET_STATION_ADDRESS";
216 return "PXENV_UNDI_SET_PACKET_FILTER";
218 return "PXENV_UNDI_GET_INFORMATION";
220 return "PXENV_UNDI_GET_STATISTICS";
222 return "PXENV_UNDI_CLEAR_STATISTICS";
224 return "PXENV_UNDI_INITIATE_DIAGS";
226 return "PXENV_UNDI_FORCE_INTERRUPT";
228 return "PXENV_UNDI_GET_MCAST_ADDRESS";
230 return "PXENV_UNDI_GET_NIC_TYPE";
232 return "PXENV_UNDI_GET_IFACE_INFO";
240 return "PXENV_UNDI_ISR";
242 return "PXENV_GET_CACHED_INFO";
244 return "UNKNOWN API CALL";
257 switch (
function ) {
259 return &undinet_tx_profiler;
261 return &undinet_isr_profiler;
263 return &undinet_unknown_profiler;
265 return &undinet_misc_profiler;
279 void *params,
size_t params_len ) {
303 "lcall *undinet_entry_point\n\t" 304 "movw %%ax, %%bx\n\t" 309 :
"=a" ( stopped ),
"=d" (
started ),
334 SEGOFF16_t rm_params = {
339 DBGC ( undinic,
"UNDINIC %p %s failed: %s\n", undinic,
341 DBGC ( undinic,
"UNDINIC %p parameters at %04x:%04x length " 342 "%#02zx, entry point at %04x:%04x\n", undinic,
343 rm_params.segment, rm_params.offset, params_len,
346 DBGC ( undinic,
"UNDINIC %p parameters provided:\n", undinic );
347 DBGC_HDA ( undinic, rm_params, params, params_len );
348 DBGC ( undinic,
"UNDINIC %p parameters returned:\n", undinic );
374 #define undiisr_irq __use_data16 ( undiisr_irq ) 378 #define undiisr_imr __use_data16 ( undiisr_imr ) 382 #define undiisr_bit __use_data16 ( undiisr_bit ) 386 #define undiisr_rearm __use_data16 ( undiisr_rearm ) 390 #define undiisr_next_handler __use_data16 ( undiisr_next_handler ) 394 #define undiisr_trigger_count __use_data16 ( undiisr_trigger_count ) 437 unsigned int this_trigger_count;
461 #define undinet_tbd __use_data16 ( undinet_tbd ) 465 #define undinet_destaddr __use_data16 ( undinet_destaddr ) 479 const void *ll_source;
503 &net_proto, &
flags ) ) != 0 ) {
504 DBGC ( undinic,
"UNDINIC %p could not strip Ethernet header: " 509 switch ( net_proto ) {
533 memset ( &undi_transmit, 0,
sizeof ( undi_transmit ) );
549 sizeof ( undi_transmit ) ) ) != 0 )
611 enable_irq ( undinic->
irq );
641 sizeof ( undi_isr ) ) ) != 0 ) {
656 if ( (
len == 0 ) || (
len < frag_len ) ) {
658 DBGC ( undinic,
"UNDINIC %p reported insane " 659 "fragment (%zd of %zd bytes)\n",
660 undinic, frag_len,
len );
667 DBGC ( undinic,
"UNDINIC %p could not " 668 "allocate %zd bytes for RX " 669 "buffer\n", undinic,
len );
677 if ( frag_len > max_frag_len ) {
678 DBGC ( undinic,
"UNDINIC %p fragment too big " 679 "(%zd+%zd does not fit into %zd)\n",
680 undinic,
iob_len ( iobuf ), frag_len,
681 (
iob_len ( iobuf ) + max_frag_len ) );
682 frag_len = max_frag_len;
685 undi_isr.
Frame.segment,
686 undi_isr.
Frame.offset, frag_len );
705 DBGC ( undinic,
"UNDINIC %p ISR returned invalid " 706 "FuncFlag %04x\n", undinic, undi_isr.
FuncFlag );
715 DBGC ( undinic,
"UNDINIC %p returned incomplete packet " 716 "(%zd of %zd)\n", undinic,
iob_len ( iobuf ),
735 if ( undinic->
irq ) {
737 enable_irq ( undinic->
irq );
749 &undi_set_address,
sizeof ( undi_set_address ) );
756 memset ( &undi_open, 0,
sizeof ( undi_open ) );
759 sizeof ( undi_open ) ) ) != 0 )
762 DBGC ( undinic,
"UNDINIC %p opened\n", undinic );
785 sizeof ( undi_isr ) ) ) != 0 )
801 sizeof ( undi_close ) );
804 if ( undinic->
irq ) {
805 disable_irq ( undinic->
irq );
809 DBGC ( undinic,
"UNDINIC %p closed\n", undinic );
822 DBGC ( undinic,
"UNDINIC %p cannot %s interrupts\n",
823 undinic, ( enable ?
"enable" :
"disable" ) );
902 DBGC ( undinic,
"UNDINIC %p %04x:%04x subsys " 903 "%04x:%04x has broken interrupts\n",
904 undinic,
desc->vendor,
desc->device,
905 subsys_vendor, subsys );
916 DBGC ( undinic,
"UNDINIC %p is PCI Express: assuming " 917 "interrupts are unreliable\n", undinic );
953 memset ( undinic, 0,
sizeof ( *undinic ) );
955 DBGC ( undinic,
"UNDINIC %p using UNDI %p\n", undinic, undi );
959 memset ( &start_undi, 0,
sizeof ( start_undi ) );
967 sizeof ( start_undi ) ) ) != 0 )
974 memset ( &undi_startup, 0,
sizeof ( undi_startup ) );
977 sizeof ( undi_startup ) ) ) != 0 )
978 goto err_undi_startup;
985 for ( retry = 0 ; ; ) {
986 memset ( &undi_init, 0,
sizeof ( undi_init ) );
990 sizeof ( undi_init ) ) ) ==0)
993 goto err_undi_initialize;
994 DBGC ( undinic,
"UNDINIC %p retrying " 995 "PXENV_UNDI_INITIALIZE (retry %d)\n",
1004 memset ( &undi_info, 0,
sizeof ( undi_info ) );
1006 &undi_info,
sizeof ( undi_info ) ) ) != 0 )
1007 goto err_undi_get_information;
1012 DBGC ( undinic,
"UNDINIC %p ignoring invalid IRQ %d\n",
1013 undinic, undinic->
irq );
1016 DBGC ( undinic,
"UNDINIC %p has MAC address %s and IRQ %d\n",
1018 if ( undinic->
irq ) {
1020 assert ( ! irq_enabled ( undinic->
irq ) );
1024 memset ( &undi_iface, 0,
sizeof ( undi_iface ) );
1026 &undi_iface,
sizeof ( undi_iface ) ) ) != 0 )
1027 goto err_undi_get_iface_info;
1028 DBGC ( undinic,
"UNDINIC %p has type %s, speed %d, flags %08x\n",
1032 ( undinic->
irq != 0 ) ) {
1035 DBGC ( undinic,
"UNDINIC %p using %s mode\n", undinic,
1038 sizeof ( undi_iface.
IfaceType ) ) == 0 ) {
1039 DBGC ( undinic,
"UNDINIC %p Etherboot 5.4 workaround enabled\n",
1044 DBGC ( undinic,
"UNDINIC %p forcing polling mode due to " 1045 "broken interrupts\n", undinic );
1056 DBGC ( undinic,
"UNDINIC %p added\n", undinic );
1060 err_undi_get_iface_info:
1061 err_undi_get_information:
1062 err_undi_initialize:
1064 memset ( &undi_shutdown, 0,
sizeof ( undi_shutdown ) );
1066 sizeof ( undi_shutdown ) );
1067 memset ( &undi_cleanup, 0,
sizeof ( undi_cleanup ) );
1069 sizeof ( undi_cleanup ) );
1073 memset ( &stop_undi, 0,
sizeof ( stop_undi ) );
1075 sizeof ( stop_undi ) );
1105 memset ( &undi_shutdown, 0,
sizeof ( undi_shutdown ) );
1107 &undi_shutdown,
sizeof ( undi_shutdown ) );
1108 memset ( &undi_cleanup, 0,
sizeof ( undi_cleanup ) );
1110 &undi_cleanup,
sizeof ( undi_cleanup ) );
1114 memset ( &stop_undi, 0,
sizeof ( stop_undi ) );
1116 sizeof ( stop_undi ) );
1127 DBGC ( undinic,
"UNDINIC %p removed\n", undinic );
#define UNDI_HACK_EB54
Work around Etherboot 5.4 bugs.
#define PXENV_UNDI_SHUTDOWN
PXE API function code for pxenv_undi_shutdown()
#define EINVAL
Invalid argument.
Parameter block for pxenv_undi_isr()
#define PXENV_UNDI_FORCE_INTERRUPT
PXE API function code for pxenv_undi_force_interrupt()
struct arbelprm_rc_send_wqe rc
static void netdev_tx_complete(struct net_device *netdev, struct io_buffer *iobuf)
Complete network transmission.
#define iob_put(iobuf, len)
void netdev_rx_err(struct net_device *netdev, struct io_buffer *iobuf, int rc)
Discard received packet.
A transmit buffer descriptor, as pointed to by s_PXENV_UNDI_TRANSMIT::TBD.
FILE_LICENCE(GPL2_OR_LATER)
#define SUPPORTED_IRQ
Interrupt Request supported.
#define PXENV_UNDI_CLEANUP
PXE API function code for pxenv_undi_cleanup()
#define PXENV_UNDI_SET_STATION_ADDRESS
PXE API function code for pxenv_undi_set_station_address()
int(* open)(struct net_device *netdev)
Open network device.
#define PXENV_START_UNDI
PXE API function code for pxenv_start_undi()
#define PXENV_UNDI_CLEAR_STATISTICS
PXE API function code for pxenv_undi_clear_statistics()
#define undiisr_trigger_count
#define PXENV_STOP_UNDI
PXE API function code for pxenv_stop_undi()
#define iob_push(iobuf, len)
#define PXENV_UNDI_GET_MCAST_ADDRESS
PXE API function code for pxenv_undi_get_mcast_address()
#define FLTR_PRMSCS
Accept all packets; listen in promiscuous mode.
int undinet_probe(struct undi_device *undi, struct device *dev)
Probe UNDI device.
Parameter block for pxenv_undi_initialize()
#define PXENV_UNDI_GET_IFACE_INFO
PXE API function code for pxenv_undi_get_iface_info()
static void undinet_poll(struct net_device *netdev)
Poll for received packets.
uint16_t pci_subsys_vendor
PCI subsystem vendor ID.
Parameter block for pxenv_undi_transmit()
int32_t before
Initial microcode version.
#define PXENV_UNDI_SET_MCAST_ADDRESS
PXE API function code for pxenv_undi_set_mcast_address()
#define UNDI_FL_INITIALIZED
UNDI flag: UNDI_STARTUP and UNDI_INITIALIZE have been called.
void send_eoi(unsigned int irq)
Send End-Of-Interrupt to the PIC.
static int undinet_irq_is_broken(struct net_device *netdev)
Check for devices with broken support for generating interrupts.
int pci_read_config_word(struct pci_device *pci, unsigned int where, uint16_t *value)
Read 16-bit word from PCI configuration space.
static void * undi_get_drvdata(struct undi_device *undi)
Get UNDI driver-private data.
static unsigned long profile_started(struct profiler *profiler)
Get start time.
UNDI network device driver.
UINT32_t ServiceFlags
Service flags.
A data structure for storing profiling information.
#define XMT_BROADCAST
Broadcast packet.
UINT16_t PktFilter
Receive packet filter.
#define PXENV_UNDI_GET_NIC_TYPE
PXE API function code for pxenv_undi_get_nic_type()
static void profile_stop(struct profiler *profiler)
Stop profiling.
int strncmp(const char *first, const char *second, size_t max)
Compare strings.
struct io_buffer * alloc_iob(size_t len)
Allocate I/O buffer.
UINT16_t FuncFlag
Function flag.
UINT32_t LinkSpeed
Link speed, in bits per second.
static void undinet_close(struct net_device *netdev)
Close NIC.
#define PCI_SUBSYSTEM_ID
PCI subsystem ID.
struct device dev
Generic device.
#define PXENV_UNKNOWN
PXE API invalid function code.
int eth_pull(struct net_device *netdev __unused, struct io_buffer *iobuf, const void **ll_dest, const void **ll_source, uint16_t *net_proto, unsigned int *flags)
Remove Ethernet link-layer header.
A hardware device description.
void undinet_remove(struct undi_device *undi)
Remove UNDI device.
#define PXENV_UNDI_ISR_OUT_RECEIVE
A packet has been received.
SEGSEL_t ES
es register as passed to the Option ROM initialisation routine.
void hook_bios_interrupt(unsigned int interrupt, unsigned int handler, struct segoff *chain_vector)
Hook INT vector.
Parameter block for pxenv_undi_close()
UINT16_t isapnp_csn
ISAPnP card select number, or UNDI_NO_ISAPNP_CSN.
static struct profiler undinet_irq_profiler __profiler
IRQ profiler.
static void profile_stop_at(struct profiler *profiler, unsigned long stopped)
Stop profiling.
static int undinet_isr_triggered(void)
Test to see if UNDI ISR has been triggered.
static void netdev_init(struct net_device *netdev, struct net_device_operations *op)
Initialise a network device.
OFF16_t DI
di register as passed to the Option ROM initialisation routine.
struct ena_llq_option desc
Descriptor counts.
int unhook_bios_interrupt(unsigned int interrupt, unsigned int handler, struct segoff *chain_vector)
Unhook INT vector.
#define PXENV_UNDI_ISR_IN_PROCESS
Start processing interrupt.
#define ENOMEM
Not enough space.
#define iob_disown(iobuf)
Disown an I/O buffer.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
static int started
"startup() has been called" flag
UINT16_t PXENV_EXIT_t
A PXE exit code.
uint16_t pci_vendor
PCI vendor ID.
static unsigned int last_trigger_count
Last observed trigger count.
UINT16_t FrameLength
Total frame length.
#define BUS_TYPE_PCI
PCI bus type.
static struct undinet_profiler * undinet_profiler(unsigned int function)
Determine applicable profiler pair (for debugging)
static int undinet_transmit(struct net_device *netdev, struct io_buffer *iobuf)
Transmit packet.
#define PXENV_UNDI_CLOSE
PXE API function code for pxenv_undi_close()
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
static void netdev_put(struct net_device *netdev)
Drop reference to network device.
UINT8_t Protocol
Protocol.
void * priv
Driver private data.
SEGOFF16_t DestAddr
Destination MAC address.
UINT8_t XmitFlag
Unicast/broadcast flag.
static void netdev_link_up(struct net_device *netdev)
Mark network device as having link up.
#define FLTR_BRDCST
Accept broadcast packets.
Parameter block for pxenv_undi_set_station_address()
#define UNDI_FL_KEEP_ALL
UNDI flag: keep stack resident.
static struct net_device * netdev
static void undinet_hook_isr(unsigned int irq)
Hook UNDI interrupt service routine.
SEGOFF16_t Frame
Data buffer address.
#define UNDI_RX_ALIGN
Alignment of received frame payload.
Parameter block for pxenv_undi_shutdown()
unsigned int irq
Assigned IRQ number.
static void profile_start(struct profiler *profiler)
Start profiling.
UINT16_t BX
bx register as passed to the Option ROM initialisation routine.
void unregister_netdev(struct net_device *netdev)
Unregister network device.
#define PXENV_UNDI_ISR_OUT_TRANSMIT
A packet transmission has completed.
Parameter block for pxenv_undi_startup()
#define PXENV_UNDI_TRANSMIT
PXE API function code for pxenv_undi_transmit()
SEGOFF16_t entry
Entry point.
static uint8_t __data16_array(undinet_destaddr, [ETH_ALEN])
UNDI transmit destination address.
char * strerror(int errno)
Retrieve string representation of error number.
int hacks
Bug workarounds.
int register_netdev(struct net_device *netdev)
Register network device.
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
const char * eth_ntoa(const void *ll_addr)
Transcribe Ethernet address.
static const char * undinet_function_name(unsigned int function)
Name PXE API call.
static union u_PXENV_ANY __bss16(undinet_params)
UNDI parameter block.
__asm__ __volatile__("call *%9" :"=a"(result), "=c"(discard_ecx), "=d"(discard_edx) :"d"(0), "a"(code), "b"(0), "c"(in_phys), "D"(0), "S"(out_phys), "m"(hypercall))
UINT16_t isapnp_read_port
ISAPnP read port, or UNDI_NO_ISAPNP_READ_PORT.
static size_t iob_tailroom(struct io_buffer *iobuf)
Calculate available space at end of an I/O buffer.
static void netdev_nullify(struct net_device *netdev)
Stop using a network device.
#define PXENV_UNDI_GET_STATISTICS
PXE API function code for pxenv_undi_get_statistics()
#define PXENV_UNDI_SET_PACKET_FILTER
PXE API function code for pxenv_undi_set_packet_filter()
#define PXENV_UNDI_INITIATE_DIAGS
PXE API function code for pxenv_undi_initiate_diags()
#define PXENV_UNDI_OPEN
PXE API function code for pxenv_undi_open()
static void undinet_irq(struct net_device *netdev, int enable)
Enable/disable interrupts.
#define XMT_DESTADDR
Unicast packet.
MAC_ADDR_t StationAddress
Station MAC address.
struct profiler r2p
Time spent transitioning back to protected mode.
#define PXENV_UNDI_ISR_IN_GET_NEXT
Continue processing interrupt.
struct profiler ext
Time spent in external code.
static int undinet_call(struct undi_nic *undinic, unsigned int function, void *params, size_t params_len)
Issue UNDI API call.
#define PCI_CAP_ID_EXP
PCI Express.
Network device operations.
void netdev_rx(struct net_device *netdev, struct io_buffer *iobuf)
Add packet to receive queue.
struct device * dev
Underlying hardware device.
#define LL_BROADCAST
Packet is a broadcast packet.
UINT16_t pci_busdevfn
PCI bus:dev.fn, or UNDI_NO_PCI_BUSDEVFN.
#define PXENV_EXIT_SUCCESS
No error occurred.
Network device management.
Parameter block for pxenv_undi_cleanup()
#define RDTSC_IF_PROFILING
static const struct undinet_irq_broken undinet_irq_broken_list[]
List of devices with broken support for generating interrupts.
#define UNDI_INITIALIZE_RETRY_MAX
Maximum number of times to retry PXENV_UNDI_INITIALIZE.
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
#define iob_reserve(iobuf, len)
static void profile_start_at(struct profiler *profiler, unsigned long started)
Start profiling.
__asm__(".section \".rodata\", \"a\", " PROGBITS "\n\t" "\nprivate_key_data:\n\t" ".size private_key_data, ( . - private_key_data )\n\t" ".equ private_key_len, ( . - private_key_data )\n\t" ".previous\n\t")
uint16_t pci_device
PCI device ID.
#define FLTR_DIRECTED
Accept "directed" packets.
static unsigned long profile_stopped(struct profiler *profiler)
Get stop time.
#define PXENV_UNDI_RESET_ADAPTER
PXE API function code for pxenv_undi_reset_adapter()
#define __from_data16(pointer)
static void undinet_unhook_isr(unsigned int irq)
Unhook UNDI interrupt service routine.
struct profiler total
Total time spent performing REAL_CALL()
SEGOFF16_t TBD
Address of the Transmit Buffer Descriptor.
int32_t after
Final microcode version.
void * data
Start of data.
#define PXENV_UNDI_ISR
PXE API function code for pxenv_undi_isr()
int find_pnp_bios(void)
Locate Plug-and-Play BIOS.
struct net_device * alloc_etherdev(size_t priv_size)
Allocate Ethernet device.
Parameter block for pxenv_undi_get_iface_info()
#define undinet_entry_point
struct device_description desc
Device description.
#define P_RARP
RARP protocol.
uint8_t __data16(undiisr_irq)
IRQ number.
#define PXENV_GET_CACHED_INFO
PXE API function code for pxenv_get_cached_info()
int isr_processing
Currently processing ISR.
#define PXENV_UNDI_ISR_OUT_DONE
Finished processing interrupt.
#define undiisr_next_handler
uint16_t protocol
Protocol ID.
#define PCI_SUBSYSTEM_VENDOR_ID
PCI subsystem vendor ID.
static void undi_set_drvdata(struct undi_device *undi, void *priv)
Set UNDI driver-private data.
void undiisr(void)
UNDI interrupt service routine.
uint8_t ll_addr[MAX_LL_ADDR_LEN]
Link-layer address.
UINT8_t IfaceType[16]
Interface type.
#define P_ARP
ARP protocol.
Parameter block for pxenv_start_undi()
#define P_UNKNOWN
Media header already filled in.
static void pci_init(struct pci_device *pci, unsigned int busdevfn)
Initialise PCI device.
#define PXENV_UNDI_STARTUP
PXE API function code for pxenv_undi_startup()
#define UNDI_RX_QUOTA
Maximum number of received packets per poll.
UINT16_t AX
ax register as passed to the Option ROM initialisation routine.
#define PXENV_UNDI_INITIALIZE
PXE API function code for pxenv_undi_initialize()
uint16_t pci_subsys
PCI subsystem ID.
UINT16_t FrameHeaderLength
Frame header length.
static struct net_device_operations undinet_operations
UNDI network device operations.
An Ethernet link-layer header.
#define REAL_CODE(asm_code_str)
uint8_t hw_addr[MAX_HW_ADDR_LEN]
Hardware address.
#define NULL
NULL pointer (VOID *)
#define UNDI_INITIALIZE_RETRY_DELAY_MS
Delay between retries of PXENV_UNDI_INITIALIZE.
UINT16_t DX
dx register as passed to the Option ROM initialisation routine.
UINT16_t BufferLength
Data buffer length.
#define UNDI_FL_STARTED
UNDI flag: START_UNDI has been called.
Parameter block for pxenv_stop_undi()
struct bofm_section_header done
Parameter block for pxenv_undi_open()
static int undinet_open(struct net_device *netdev)
Open NIC.
#define PCI_ANY_ID
Match-anything ID.
A device with broken support for generating interrupts.
int irq_supported
Device supports IRQs.
A PXE API call breakdown profiler.
void * memset(void *dest, int character, size_t len) __nonnull
struct profiler p2r
Time spent transitioning to real mode.