/* This file is part of the program psim.
|
/* This file is part of the program psim.
|
|
|
Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
|
Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
|
|
|
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
the Free Software Foundation; either version 2 of the License, or
|
the Free Software Foundation; either version 2 of the License, or
|
(at your option) any later version.
|
(at your option) any later version.
|
|
|
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
GNU General Public License for more details.
|
GNU General Public License for more details.
|
|
|
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
*/
|
*/
|
|
|
|
|
#ifndef _HW_HTAB_C_
|
#ifndef _HW_HTAB_C_
|
#define _HW_HTAB_C_
|
#define _HW_HTAB_C_
|
|
|
#include "device_table.h"
|
#include "device_table.h"
|
|
|
#include "bfd.h"
|
#include "bfd.h"
|
|
|
|
|
/* DEVICE
|
/* DEVICE
|
|
|
|
|
htab - pseudo-device describing a PowerPC hash table
|
htab - pseudo-device describing a PowerPC hash table
|
|
|
|
|
DESCRIPTION
|
DESCRIPTION
|
|
|
|
|
During the initialization of the device tree, the pseudo-device
|
During the initialization of the device tree, the pseudo-device
|
<<htab>>, in conjunction with any child <<pte>> pseudo-devices,
|
<<htab>>, in conjunction with any child <<pte>> pseudo-devices,
|
will create a PowerPC hash table in memory. The hash table values
|
will create a PowerPC hash table in memory. The hash table values
|
are written using dma transfers.
|
are written using dma transfers.
|
|
|
The size and address of the hash table are determined by properties
|
The size and address of the hash table are determined by properties
|
of the htab node.
|
of the htab node.
|
|
|
By convention, the htab device is made a child of the
|
By convention, the htab device is made a child of the
|
<</openprom/init>> node.
|
<</openprom/init>> node.
|
|
|
By convention, the real address of the htab is used as the htab
|
By convention, the real address of the htab is used as the htab
|
nodes unit address.
|
nodes unit address.
|
|
|
|
|
PROPERTIES
|
PROPERTIES
|
|
|
|
|
real-address = <address> (required)
|
real-address = <address> (required)
|
|
|
The physical address of the hash table. The PowerPC architecture
|
The physical address of the hash table. The PowerPC architecture
|
places limitations on what is a valid hash table real-address.
|
places limitations on what is a valid hash table real-address.
|
|
|
|
|
nr-bytes = <size> (required)
|
nr-bytes = <size> (required)
|
|
|
The size of the hash table (in bytes) that is to be created at
|
The size of the hash table (in bytes) that is to be created at
|
<<real-address>>. The PowerPC architecture places limitations on
|
<<real-address>>. The PowerPC architecture places limitations on
|
what is a valid hash table size.
|
what is a valid hash table size.
|
|
|
|
|
claim = <anything> (optional)
|
claim = <anything> (optional)
|
|
|
If this property is present, the memory used to construct the hash
|
If this property is present, the memory used to construct the hash
|
table will be claimed from the memory device. The memory device
|
table will be claimed from the memory device. The memory device
|
being specified by the <</chosen/memory>> ihandle property.
|
being specified by the <</chosen/memory>> ihandle property.
|
|
|
|
|
EXAMPLES
|
EXAMPLES
|
|
|
Enable tracing.
|
Enable tracing.
|
|
|
| $ psim -t htab-device \
|
| $ psim -t htab-device \
|
|
|
|
|
Create a htab specifying the base address and minimum size.
|
Create a htab specifying the base address and minimum size.
|
|
|
| -o '/openprom/init/htab@0x10000/real-address 0x10000' \
|
| -o '/openprom/init/htab@0x10000/real-address 0x10000' \
|
| -o '/openprom/init/htab@0x10000/claim 0' \
|
| -o '/openprom/init/htab@0x10000/claim 0' \
|
| -o '/openprom/init/htab@0x10000/nr-bytes 65536' \
|
| -o '/openprom/init/htab@0x10000/nr-bytes 65536' \
|
|
|
|
|
BUGS
|
BUGS
|
|
|
|
|
See the <<pte>> device.
|
See the <<pte>> device.
|
|
|
|
|
*/
|
*/
|
|
|
|
|
/* DEVICE
|
/* DEVICE
|
|
|
|
|
pte - pseudo-device describing a htab entry
|
pte - pseudo-device describing a htab entry
|
|
|
|
|
DESCRIPTION
|
DESCRIPTION
|
|
|
|
|
The <<pte>> pseudo-device, which must be a child of a <<htabl>>
|
The <<pte>> pseudo-device, which must be a child of a <<htabl>>
|
node, describes a virtual to physical mapping that is to be entered
|
node, describes a virtual to physical mapping that is to be entered
|
into the parents hash table.
|
into the parents hash table.
|
|
|
Two alternative specifications of the mapping are allowed. Either
|
Two alternative specifications of the mapping are allowed. Either
|
a section of physical memory can be mapped to a virtual address, or
|
a section of physical memory can be mapped to a virtual address, or
|
the header of an executible image can be used to define the
|
the header of an executible image can be used to define the
|
mapping.
|
mapping.
|
|
|
By convention, the real address of the map is specified as the pte
|
By convention, the real address of the map is specified as the pte
|
devices unit address.
|
devices unit address.
|
|
|
|
|
PROPERTIES
|
PROPERTIES
|
|
|
|
|
real-address = <address> (required)
|
real-address = <address> (required)
|
|
|
The starting physical address that is to be mapped by the hash
|
The starting physical address that is to be mapped by the hash
|
table.
|
table.
|
|
|
|
|
wimg = <int> (required)
|
wimg = <int> (required)
|
pp = <int> (required)
|
pp = <int> (required)
|
|
|
The value of hash table protection bits that are to be used when
|
The value of hash table protection bits that are to be used when
|
creating the virtual to physical address map.
|
creating the virtual to physical address map.
|
|
|
|
|
claim = <anything> (optional)
|
claim = <anything> (optional)
|
|
|
If this property is present, the real memory that is being mapped by the
|
If this property is present, the real memory that is being mapped by the
|
hash table will be claimed from the memory node (specified by the
|
hash table will be claimed from the memory node (specified by the
|
ihandle <</chosen/memory>>).
|
ihandle <</chosen/memory>>).
|
|
|
|
|
virtual-address = <integer> [ <integer> ] (option A)
|
virtual-address = <integer> [ <integer> ] (option A)
|
nr-bytes = <size> (option A)
|
nr-bytes = <size> (option A)
|
|
|
Option A - Virtual virtual address (and size) at which the physical
|
Option A - Virtual virtual address (and size) at which the physical
|
address is to be mapped. If multiple values are specified for the
|
address is to be mapped. If multiple values are specified for the
|
virtual address then they are concatenated to gether to form a
|
virtual address then they are concatenated to gether to form a
|
longer virtual address.
|
longer virtual address.
|
|
|
|
|
file-name = <string> (option B)
|
file-name = <string> (option B)
|
|
|
Option B - An executable image that is to be loaded (starting at
|
Option B - An executable image that is to be loaded (starting at
|
the physical address specified above) and then mapped in using
|
the physical address specified above) and then mapped in using
|
informatioin taken from the executables header. information found
|
informatioin taken from the executables header. information found
|
in the files header.
|
in the files header.
|
|
|
|
|
EXAMPLES
|
EXAMPLES
|
|
|
|
|
Enable tracing (note that both the <<htab>> and <<pte>> device use the
|
Enable tracing (note that both the <<htab>> and <<pte>> device use the
|
same trace option).
|
same trace option).
|
|
|
| -t htab-device \
|
| -t htab-device \
|
|
|
|
|
Map a block of physical memory into a specified virtual address:
|
Map a block of physical memory into a specified virtual address:
|
|
|
| -o '/openprom/init/htab/pte@0x0/real-address 0' \
|
| -o '/openprom/init/htab/pte@0x0/real-address 0' \
|
| -o '/openprom/init/htab/pte@0x0/nr-bytes 4096' \
|
| -o '/openprom/init/htab/pte@0x0/nr-bytes 4096' \
|
| -o '/openprom/init/htab/pte@0x0/virtual-address 0x1000000' \
|
| -o '/openprom/init/htab/pte@0x0/virtual-address 0x1000000' \
|
| -o '/openprom/init/htab/pte@0x0/claim 0' \
|
| -o '/openprom/init/htab/pte@0x0/claim 0' \
|
| -o '/openprom/init/htab/pte@0x0/wimg 0x7' \
|
| -o '/openprom/init/htab/pte@0x0/wimg 0x7' \
|
| -o '/openprom/init/htab/pte@0x0/pp 0x2' \
|
| -o '/openprom/init/htab/pte@0x0/pp 0x2' \
|
|
|
|
|
Map a file into memory.
|
Map a file into memory.
|
|
|
| -o '/openprom/init/htab/pte@0x10000/real-address 0x10000' \
|
| -o '/openprom/init/htab/pte@0x10000/real-address 0x10000' \
|
| -o '/openprom/init/htab/pte@0x10000/file-name "netbsd.elf' \
|
| -o '/openprom/init/htab/pte@0x10000/file-name "netbsd.elf' \
|
| -o '/openprom/init/htab/pte@0x10000/wimg 0x7' \
|
| -o '/openprom/init/htab/pte@0x10000/wimg 0x7' \
|
| -o '/openprom/init/htab/pte@0x10000/pp 0x2' \
|
| -o '/openprom/init/htab/pte@0x10000/pp 0x2' \
|
|
|
|
|
BUGS
|
BUGS
|
|
|
|
|
For an ELF executable, the header defines both the virtual and real
|
For an ELF executable, the header defines both the virtual and real
|
address at which each file section should be loaded. At present, the
|
address at which each file section should be loaded. At present, the
|
real addresses that are specified in the header are ignored, the file
|
real addresses that are specified in the header are ignored, the file
|
instead being loaded in to physical memory in a linear fashion.
|
instead being loaded in to physical memory in a linear fashion.
|
|
|
When claiming memory, this device assumes that the #address-cells
|
When claiming memory, this device assumes that the #address-cells
|
and #size-cells is one. For future implementations, this may not
|
and #size-cells is one. For future implementations, this may not
|
be the case.
|
be the case.
|
|
|
*/
|
*/
|
|
|
|
|
|
|
static void
|
static void
|
htab_decode_hash_table(device *me,
|
htab_decode_hash_table(device *me,
|
unsigned32 *htaborg,
|
unsigned32 *htaborg,
|
unsigned32 *htabmask)
|
unsigned32 *htabmask)
|
{
|
{
|
unsigned_word htab_ra;
|
unsigned_word htab_ra;
|
unsigned htab_nr_bytes;
|
unsigned htab_nr_bytes;
|
unsigned n;
|
unsigned n;
|
device *parent = device_parent(me);
|
device *parent = device_parent(me);
|
/* determine the location/size of the hash table */
|
/* determine the location/size of the hash table */
|
if (parent == NULL
|
if (parent == NULL
|
|| strcmp(device_name(parent), "htab") != 0)
|
|| strcmp(device_name(parent), "htab") != 0)
|
device_error(parent, "must be a htab device");
|
device_error(parent, "must be a htab device");
|
htab_ra = device_find_integer_property(parent, "real-address");
|
htab_ra = device_find_integer_property(parent, "real-address");
|
htab_nr_bytes = device_find_integer_property(parent, "nr-bytes");
|
htab_nr_bytes = device_find_integer_property(parent, "nr-bytes");
|
for (n = htab_nr_bytes; n > 1; n = n / 2) {
|
for (n = htab_nr_bytes; n > 1; n = n / 2) {
|
if (n % 2 != 0)
|
if (n % 2 != 0)
|
device_error(parent, "htab size 0x%x not a power of two",
|
device_error(parent, "htab size 0x%x not a power of two",
|
htab_nr_bytes);
|
htab_nr_bytes);
|
}
|
}
|
*htaborg = htab_ra;
|
*htaborg = htab_ra;
|
*htabmask = MASKED32(htab_nr_bytes - 1, 7, 31-6);
|
*htabmask = MASKED32(htab_nr_bytes - 1, 7, 31-6);
|
if ((htab_ra & INSERTED32(*htabmask, 7, 15)) != 0) {
|
if ((htab_ra & INSERTED32(*htabmask, 7, 15)) != 0) {
|
device_error(parent, "htaborg 0x%lx not aligned to htabmask 0x%lx",
|
device_error(parent, "htaborg 0x%lx not aligned to htabmask 0x%lx",
|
(unsigned long)*htaborg, (unsigned long)*htabmask);
|
(unsigned long)*htaborg, (unsigned long)*htabmask);
|
}
|
}
|
DTRACE(htab, ("htab - htaborg=0x%lx htabmask=0x%lx\n",
|
DTRACE(htab, ("htab - htaborg=0x%lx htabmask=0x%lx\n",
|
(unsigned long)*htaborg, (unsigned long)*htabmask));
|
(unsigned long)*htaborg, (unsigned long)*htabmask));
|
}
|
}
|
|
|
static void
|
static void
|
htab_map_page(device *me,
|
htab_map_page(device *me,
|
unsigned_word ra,
|
unsigned_word ra,
|
unsigned64 va,
|
unsigned64 va,
|
unsigned wimg,
|
unsigned wimg,
|
unsigned pp,
|
unsigned pp,
|
unsigned32 htaborg,
|
unsigned32 htaborg,
|
unsigned32 htabmask)
|
unsigned32 htabmask)
|
{
|
{
|
/* keep everything left shifted so that the numbering is easier */
|
/* keep everything left shifted so that the numbering is easier */
|
unsigned64 vpn = va << 12;
|
unsigned64 vpn = va << 12;
|
unsigned32 vsid = INSERTED32(EXTRACTED64(vpn, 0, 23), 0, 23);
|
unsigned32 vsid = INSERTED32(EXTRACTED64(vpn, 0, 23), 0, 23);
|
unsigned32 vpage = INSERTED32(EXTRACTED64(vpn, 24, 39), 0, 15);
|
unsigned32 vpage = INSERTED32(EXTRACTED64(vpn, 24, 39), 0, 15);
|
unsigned32 hash = INSERTED32(EXTRACTED32(vsid, 5, 23)
|
unsigned32 hash = INSERTED32(EXTRACTED32(vsid, 5, 23)
|
^ EXTRACTED32(vpage, 0, 15),
|
^ EXTRACTED32(vpage, 0, 15),
|
7, 31-6);
|
7, 31-6);
|
int h;
|
int h;
|
for (h = 0; h < 2; h++) {
|
for (h = 0; h < 2; h++) {
|
unsigned32 pteg = (htaborg | (hash & htabmask));
|
unsigned32 pteg = (htaborg | (hash & htabmask));
|
int pti;
|
int pti;
|
for (pti = 0; pti < 8; pti++) {
|
for (pti = 0; pti < 8; pti++) {
|
unsigned32 pte = pteg + 8 * pti;
|
unsigned32 pte = pteg + 8 * pti;
|
unsigned32 current_target_pte0;
|
unsigned32 current_target_pte0;
|
unsigned32 current_pte0;
|
unsigned32 current_pte0;
|
if (device_dma_read_buffer(device_parent(me),
|
if (device_dma_read_buffer(device_parent(me),
|
¤t_target_pte0,
|
¤t_target_pte0,
|
0, /*space*/
|
0, /*space*/
|
pte,
|
pte,
|
sizeof(current_target_pte0)) != 4)
|
sizeof(current_target_pte0)) != 4)
|
device_error(me, "failed to read a pte at 0x%lx", (unsigned long)pte);
|
device_error(me, "failed to read a pte at 0x%lx", (unsigned long)pte);
|
current_pte0 = T2H_4(current_target_pte0);
|
current_pte0 = T2H_4(current_target_pte0);
|
if (MASKED32(current_pte0, 0, 0)) {
|
if (MASKED32(current_pte0, 0, 0)) {
|
/* full pte, check it isn't already mapping the same virtual
|
/* full pte, check it isn't already mapping the same virtual
|
address */
|
address */
|
unsigned32 curr_vsid = INSERTED32(EXTRACTED32(current_pte0, 1, 24), 0, 23);
|
unsigned32 curr_vsid = INSERTED32(EXTRACTED32(current_pte0, 1, 24), 0, 23);
|
unsigned32 curr_api = INSERTED32(EXTRACTED32(current_pte0, 26, 31), 0, 5);
|
unsigned32 curr_api = INSERTED32(EXTRACTED32(current_pte0, 26, 31), 0, 5);
|
unsigned32 curr_h = EXTRACTED32(current_pte0, 25, 25);
|
unsigned32 curr_h = EXTRACTED32(current_pte0, 25, 25);
|
if (curr_h == h
|
if (curr_h == h
|
&& curr_vsid == vsid
|
&& curr_vsid == vsid
|
&& curr_api == MASKED32(vpage, 0, 5))
|
&& curr_api == MASKED32(vpage, 0, 5))
|
device_error(me, "duplicate map - va=0x%08lx ra=0x%lx vsid=0x%lx h=%d vpage=0x%lx hash=0x%lx pteg=0x%lx+%2d pte0=0x%lx",
|
device_error(me, "duplicate map - va=0x%08lx ra=0x%lx vsid=0x%lx h=%d vpage=0x%lx hash=0x%lx pteg=0x%lx+%2d pte0=0x%lx",
|
(unsigned long)va,
|
(unsigned long)va,
|
(unsigned long)ra,
|
(unsigned long)ra,
|
(unsigned long)vsid,
|
(unsigned long)vsid,
|
h,
|
h,
|
(unsigned long)vpage,
|
(unsigned long)vpage,
|
(unsigned long)hash,
|
(unsigned long)hash,
|
(unsigned long)pteg,
|
(unsigned long)pteg,
|
pti * 8,
|
pti * 8,
|
(unsigned long)current_pte0);
|
(unsigned long)current_pte0);
|
}
|
}
|
else {
|
else {
|
/* empty pte fill it */
|
/* empty pte fill it */
|
unsigned32 pte0 = (MASK32(0, 0)
|
unsigned32 pte0 = (MASK32(0, 0)
|
| INSERTED32(EXTRACTED32(vsid, 0, 23), 1, 24)
|
| INSERTED32(EXTRACTED32(vsid, 0, 23), 1, 24)
|
| INSERTED32(h, 25, 25)
|
| INSERTED32(h, 25, 25)
|
| INSERTED32(EXTRACTED32(vpage, 0, 5), 26, 31));
|
| INSERTED32(EXTRACTED32(vpage, 0, 5), 26, 31));
|
unsigned32 target_pte0 = H2T_4(pte0);
|
unsigned32 target_pte0 = H2T_4(pte0);
|
unsigned32 pte1 = (INSERTED32(EXTRACTED32(ra, 0, 19), 0, 19)
|
unsigned32 pte1 = (INSERTED32(EXTRACTED32(ra, 0, 19), 0, 19)
|
| INSERTED32(wimg, 25, 28)
|
| INSERTED32(wimg, 25, 28)
|
| INSERTED32(pp, 30, 31));
|
| INSERTED32(pp, 30, 31));
|
unsigned32 target_pte1 = H2T_4(pte1);
|
unsigned32 target_pte1 = H2T_4(pte1);
|
if (device_dma_write_buffer(device_parent(me),
|
if (device_dma_write_buffer(device_parent(me),
|
&target_pte0,
|
&target_pte0,
|
0, /*space*/
|
0, /*space*/
|
pte,
|
pte,
|
sizeof(target_pte0),
|
sizeof(target_pte0),
|
1/*ro?*/) != 4
|
1/*ro?*/) != 4
|
|| device_dma_write_buffer(device_parent(me),
|
|| device_dma_write_buffer(device_parent(me),
|
&target_pte1,
|
&target_pte1,
|
0, /*space*/
|
0, /*space*/
|
pte + 4,
|
pte + 4,
|
sizeof(target_pte1),
|
sizeof(target_pte1),
|
1/*ro?*/) != 4)
|
1/*ro?*/) != 4)
|
device_error(me, "failed to write a pte a 0x%lx", (unsigned long)pte);
|
device_error(me, "failed to write a pte a 0x%lx", (unsigned long)pte);
|
DTRACE(htab, ("map - va=0x%08lx ra=0x%lx vsid=0x%lx h=%d vpage=0x%lx hash=0x%lx pteg=0x%lx+%2d pte0=0x%lx pte1=0x%lx\n",
|
DTRACE(htab, ("map - va=0x%08lx ra=0x%lx vsid=0x%lx h=%d vpage=0x%lx hash=0x%lx pteg=0x%lx+%2d pte0=0x%lx pte1=0x%lx\n",
|
(unsigned long)va,
|
(unsigned long)va,
|
(unsigned long)ra,
|
(unsigned long)ra,
|
(unsigned long)vsid,
|
(unsigned long)vsid,
|
h,
|
h,
|
(unsigned long)vpage,
|
(unsigned long)vpage,
|
(unsigned long)hash,
|
(unsigned long)hash,
|
(unsigned long)pteg,
|
(unsigned long)pteg,
|
pti * 8,
|
pti * 8,
|
(unsigned long)pte0,
|
(unsigned long)pte0,
|
(unsigned long)pte1));
|
(unsigned long)pte1));
|
return;
|
return;
|
}
|
}
|
}
|
}
|
/* re-hash */
|
/* re-hash */
|
hash = MASKED32(~hash, 0, 18);
|
hash = MASKED32(~hash, 0, 18);
|
}
|
}
|
}
|
}
|
|
|
static unsigned_word
|
static unsigned_word
|
claim_memory(device *me,
|
claim_memory(device *me,
|
device_instance *memory,
|
device_instance *memory,
|
unsigned_word ra,
|
unsigned_word ra,
|
unsigned_word size)
|
unsigned_word size)
|
{
|
{
|
unsigned32 args[3];
|
unsigned32 args[3];
|
unsigned32 results[1];
|
unsigned32 results[1];
|
int status;
|
int status;
|
args[0] = 0; /* alignment */
|
args[0] = 0; /* alignment */
|
args[1] = size;
|
args[1] = size;
|
args[2] = ra;
|
args[2] = ra;
|
status = device_instance_call_method(memory, "claim", 3, args, 1, results);
|
status = device_instance_call_method(memory, "claim", 3, args, 1, results);
|
if (status != 0)
|
if (status != 0)
|
device_error(me, "failed to claim memory");
|
device_error(me, "failed to claim memory");
|
return results[0];
|
return results[0];
|
}
|
}
|
|
|
static void
|
static void
|
htab_map_region(device *me,
|
htab_map_region(device *me,
|
device_instance *memory,
|
device_instance *memory,
|
unsigned_word pte_ra,
|
unsigned_word pte_ra,
|
unsigned64 pte_va,
|
unsigned64 pte_va,
|
unsigned nr_bytes,
|
unsigned nr_bytes,
|
unsigned wimg,
|
unsigned wimg,
|
unsigned pp,
|
unsigned pp,
|
unsigned32 htaborg,
|
unsigned32 htaborg,
|
unsigned32 htabmask)
|
unsigned32 htabmask)
|
{
|
{
|
unsigned_word ra;
|
unsigned_word ra;
|
unsigned64 va;
|
unsigned64 va;
|
/* claim the memory */
|
/* claim the memory */
|
if (memory != NULL)
|
if (memory != NULL)
|
claim_memory(me, memory, pte_ra, nr_bytes);
|
claim_memory(me, memory, pte_ra, nr_bytes);
|
/* go through all pages and create a pte for each */
|
/* go through all pages and create a pte for each */
|
for (ra = pte_ra, va = pte_va;
|
for (ra = pte_ra, va = pte_va;
|
ra < pte_ra + nr_bytes;
|
ra < pte_ra + nr_bytes;
|
ra += 0x1000, va += 0x1000) {
|
ra += 0x1000, va += 0x1000) {
|
htab_map_page(me, ra, va, wimg, pp, htaborg, htabmask);
|
htab_map_page(me, ra, va, wimg, pp, htaborg, htabmask);
|
}
|
}
|
}
|
}
|
|
|
typedef struct _htab_binary_sizes {
|
typedef struct _htab_binary_sizes {
|
unsigned_word text_ra;
|
unsigned_word text_ra;
|
unsigned_word text_base;
|
unsigned_word text_base;
|
unsigned_word text_bound;
|
unsigned_word text_bound;
|
unsigned_word data_ra;
|
unsigned_word data_ra;
|
unsigned_word data_base;
|
unsigned_word data_base;
|
unsigned data_bound;
|
unsigned data_bound;
|
device *me;
|
device *me;
|
} htab_binary_sizes;
|
} htab_binary_sizes;
|
|
|
static void
|
static void
|
htab_sum_binary(bfd *abfd,
|
htab_sum_binary(bfd *abfd,
|
sec_ptr sec,
|
sec_ptr sec,
|
PTR data)
|
PTR data)
|
{
|
{
|
htab_binary_sizes *sizes = (htab_binary_sizes*)data;
|
htab_binary_sizes *sizes = (htab_binary_sizes*)data;
|
unsigned_word size = bfd_get_section_size_before_reloc (sec);
|
unsigned_word size = bfd_get_section_size_before_reloc (sec);
|
unsigned_word vma = bfd_get_section_vma (abfd, sec);
|
unsigned_word vma = bfd_get_section_vma (abfd, sec);
|
#define bfd_get_section_lma(abfd, sec) ((sec)->lma + 0)
|
#define bfd_get_section_lma(abfd, sec) ((sec)->lma + 0)
|
unsigned_word ra = bfd_get_section_lma (abfd, sec);
|
unsigned_word ra = bfd_get_section_lma (abfd, sec);
|
|
|
/* skip the section if no memory to allocate */
|
/* skip the section if no memory to allocate */
|
if (! (bfd_get_section_flags(abfd, sec) & SEC_ALLOC))
|
if (! (bfd_get_section_flags(abfd, sec) & SEC_ALLOC))
|
return;
|
return;
|
|
|
if ((bfd_get_section_flags (abfd, sec) & SEC_CODE)
|
if ((bfd_get_section_flags (abfd, sec) & SEC_CODE)
|
|| (bfd_get_section_flags (abfd, sec) & SEC_READONLY)) {
|
|| (bfd_get_section_flags (abfd, sec) & SEC_READONLY)) {
|
if (sizes->text_bound < vma + size)
|
if (sizes->text_bound < vma + size)
|
sizes->text_bound = ALIGN_PAGE(vma + size);
|
sizes->text_bound = ALIGN_PAGE(vma + size);
|
if (sizes->text_base > vma)
|
if (sizes->text_base > vma)
|
sizes->text_base = FLOOR_PAGE(vma);
|
sizes->text_base = FLOOR_PAGE(vma);
|
if (sizes->text_ra > ra)
|
if (sizes->text_ra > ra)
|
sizes->text_ra = FLOOR_PAGE(ra);
|
sizes->text_ra = FLOOR_PAGE(ra);
|
}
|
}
|
else if ((bfd_get_section_flags (abfd, sec) & SEC_DATA)
|
else if ((bfd_get_section_flags (abfd, sec) & SEC_DATA)
|
|| (bfd_get_section_flags (abfd, sec) & SEC_ALLOC)) {
|
|| (bfd_get_section_flags (abfd, sec) & SEC_ALLOC)) {
|
if (sizes->data_bound < vma + size)
|
if (sizes->data_bound < vma + size)
|
sizes->data_bound = ALIGN_PAGE(vma + size);
|
sizes->data_bound = ALIGN_PAGE(vma + size);
|
if (sizes->data_base > vma)
|
if (sizes->data_base > vma)
|
sizes->data_base = FLOOR_PAGE(vma);
|
sizes->data_base = FLOOR_PAGE(vma);
|
if (sizes->data_ra > ra)
|
if (sizes->data_ra > ra)
|
sizes->data_ra = FLOOR_PAGE(ra);
|
sizes->data_ra = FLOOR_PAGE(ra);
|
}
|
}
|
}
|
}
|
|
|
static void
|
static void
|
htab_dma_binary(bfd *abfd,
|
htab_dma_binary(bfd *abfd,
|
sec_ptr sec,
|
sec_ptr sec,
|
PTR data)
|
PTR data)
|
{
|
{
|
htab_binary_sizes *sizes = (htab_binary_sizes*)data;
|
htab_binary_sizes *sizes = (htab_binary_sizes*)data;
|
void *section_init;
|
void *section_init;
|
unsigned_word section_vma;
|
unsigned_word section_vma;
|
unsigned_word section_size;
|
unsigned_word section_size;
|
unsigned_word section_ra;
|
unsigned_word section_ra;
|
device *me = sizes->me;
|
device *me = sizes->me;
|
|
|
/* skip the section if no memory to allocate */
|
/* skip the section if no memory to allocate */
|
if (! (bfd_get_section_flags(abfd, sec) & SEC_ALLOC))
|
if (! (bfd_get_section_flags(abfd, sec) & SEC_ALLOC))
|
return;
|
return;
|
|
|
/* check/ignore any sections of size zero */
|
/* check/ignore any sections of size zero */
|
section_size = bfd_get_section_size_before_reloc(sec);
|
section_size = bfd_get_section_size_before_reloc(sec);
|
if (section_size == 0)
|
if (section_size == 0)
|
return;
|
return;
|
|
|
/* if nothing to load, ignore this one */
|
/* if nothing to load, ignore this one */
|
if (! (bfd_get_section_flags(abfd, sec) & SEC_LOAD))
|
if (! (bfd_get_section_flags(abfd, sec) & SEC_LOAD))
|
return;
|
return;
|
|
|
/* find where it is to go */
|
/* find where it is to go */
|
section_vma = bfd_get_section_vma(abfd, sec);
|
section_vma = bfd_get_section_vma(abfd, sec);
|
section_ra = 0;
|
section_ra = 0;
|
if ((bfd_get_section_flags (abfd, sec) & SEC_CODE)
|
if ((bfd_get_section_flags (abfd, sec) & SEC_CODE)
|
|| (bfd_get_section_flags (abfd, sec) & SEC_READONLY))
|
|| (bfd_get_section_flags (abfd, sec) & SEC_READONLY))
|
section_ra = (section_vma - sizes->text_base + sizes->text_ra);
|
section_ra = (section_vma - sizes->text_base + sizes->text_ra);
|
else if ((bfd_get_section_flags (abfd, sec) & SEC_DATA))
|
else if ((bfd_get_section_flags (abfd, sec) & SEC_DATA))
|
section_ra = (section_vma - sizes->data_base + sizes->data_ra);
|
section_ra = (section_vma - sizes->data_base + sizes->data_ra);
|
else
|
else
|
return; /* just ignore it */
|
return; /* just ignore it */
|
|
|
DTRACE(htab,
|
DTRACE(htab,
|
("load - name=%-7s vma=0x%.8lx size=%6ld ra=0x%.8lx flags=%3lx(%s%s%s%s%s )\n",
|
("load - name=%-7s vma=0x%.8lx size=%6ld ra=0x%.8lx flags=%3lx(%s%s%s%s%s )\n",
|
bfd_get_section_name(abfd, sec),
|
bfd_get_section_name(abfd, sec),
|
(long)section_vma,
|
(long)section_vma,
|
(long)section_size,
|
(long)section_size,
|
(long)section_ra,
|
(long)section_ra,
|
(long)bfd_get_section_flags(abfd, sec),
|
(long)bfd_get_section_flags(abfd, sec),
|
bfd_get_section_flags(abfd, sec) & SEC_LOAD ? " LOAD" : "",
|
bfd_get_section_flags(abfd, sec) & SEC_LOAD ? " LOAD" : "",
|
bfd_get_section_flags(abfd, sec) & SEC_CODE ? " CODE" : "",
|
bfd_get_section_flags(abfd, sec) & SEC_CODE ? " CODE" : "",
|
bfd_get_section_flags(abfd, sec) & SEC_DATA ? " DATA" : "",
|
bfd_get_section_flags(abfd, sec) & SEC_DATA ? " DATA" : "",
|
bfd_get_section_flags(abfd, sec) & SEC_ALLOC ? " ALLOC" : "",
|
bfd_get_section_flags(abfd, sec) & SEC_ALLOC ? " ALLOC" : "",
|
bfd_get_section_flags(abfd, sec) & SEC_READONLY ? " READONLY" : ""
|
bfd_get_section_flags(abfd, sec) & SEC_READONLY ? " READONLY" : ""
|
));
|
));
|
|
|
/* dma in the sections data */
|
/* dma in the sections data */
|
section_init = zalloc(section_size);
|
section_init = zalloc(section_size);
|
if (!bfd_get_section_contents(abfd,
|
if (!bfd_get_section_contents(abfd,
|
sec,
|
sec,
|
section_init, 0,
|
section_init, 0,
|
section_size)) {
|
section_size)) {
|
bfd_perror("devices/pte");
|
bfd_perror("devices/pte");
|
device_error(me, "no data loaded");
|
device_error(me, "no data loaded");
|
}
|
}
|
if (device_dma_write_buffer(device_parent(me),
|
if (device_dma_write_buffer(device_parent(me),
|
section_init,
|
section_init,
|
0 /*space*/,
|
0 /*space*/,
|
section_ra,
|
section_ra,
|
section_size,
|
section_size,
|
1 /*violate_read_only*/)
|
1 /*violate_read_only*/)
|
!= section_size)
|
!= section_size)
|
device_error(me, "broken dma transfer");
|
device_error(me, "broken dma transfer");
|
zfree(section_init); /* only free if load */
|
zfree(section_init); /* only free if load */
|
}
|
}
|
|
|
/* create a memory map from a binaries virtual addresses to a copy of
|
/* create a memory map from a binaries virtual addresses to a copy of
|
the binary laid out linearly in memory */
|
the binary laid out linearly in memory */
|
|
|
static void
|
static void
|
htab_map_binary(device *me,
|
htab_map_binary(device *me,
|
device_instance *memory,
|
device_instance *memory,
|
unsigned_word ra,
|
unsigned_word ra,
|
unsigned wimg,
|
unsigned wimg,
|
unsigned pp,
|
unsigned pp,
|
const char *file_name,
|
const char *file_name,
|
unsigned32 htaborg,
|
unsigned32 htaborg,
|
unsigned32 htabmask)
|
unsigned32 htabmask)
|
{
|
{
|
htab_binary_sizes sizes;
|
htab_binary_sizes sizes;
|
bfd *image;
|
bfd *image;
|
sizes.text_ra = -1;
|
sizes.text_ra = -1;
|
sizes.data_ra = -1;
|
sizes.data_ra = -1;
|
sizes.text_base = -1;
|
sizes.text_base = -1;
|
sizes.data_base = -1;
|
sizes.data_base = -1;
|
sizes.text_bound = 0;
|
sizes.text_bound = 0;
|
sizes.data_bound = 0;
|
sizes.data_bound = 0;
|
sizes.me = me;
|
sizes.me = me;
|
|
|
/* open the file */
|
/* open the file */
|
image = bfd_openr(file_name, NULL);
|
image = bfd_openr(file_name, NULL);
|
if (image == NULL) {
|
if (image == NULL) {
|
bfd_perror("devices/pte");
|
bfd_perror("devices/pte");
|
device_error(me, "the file %s not loaded", file_name);
|
device_error(me, "the file %s not loaded", file_name);
|
}
|
}
|
|
|
/* check it is valid */
|
/* check it is valid */
|
if (!bfd_check_format(image, bfd_object)) {
|
if (!bfd_check_format(image, bfd_object)) {
|
bfd_close(image);
|
bfd_close(image);
|
device_error(me, "the file %s has an invalid binary format", file_name);
|
device_error(me, "the file %s has an invalid binary format", file_name);
|
}
|
}
|
|
|
/* determine the size of each of the files regions */
|
/* determine the size of each of the files regions */
|
bfd_map_over_sections (image, htab_sum_binary, (PTR) &sizes);
|
bfd_map_over_sections (image, htab_sum_binary, (PTR) &sizes);
|
|
|
/* if needed, determine the real addresses of the sections */
|
/* if needed, determine the real addresses of the sections */
|
if (ra != -1) {
|
if (ra != -1) {
|
sizes.text_ra = ra;
|
sizes.text_ra = ra;
|
sizes.data_ra = ALIGN_PAGE(sizes.text_ra +
|
sizes.data_ra = ALIGN_PAGE(sizes.text_ra +
|
(sizes.text_bound - sizes.text_base));
|
(sizes.text_bound - sizes.text_base));
|
}
|
}
|
|
|
DTRACE(htab, ("text map - base=0x%lx bound=0x%lx-1 ra=0x%lx\n",
|
DTRACE(htab, ("text map - base=0x%lx bound=0x%lx-1 ra=0x%lx\n",
|
(unsigned long)sizes.text_base,
|
(unsigned long)sizes.text_base,
|
(unsigned long)sizes.text_bound,
|
(unsigned long)sizes.text_bound,
|
(unsigned long)sizes.text_ra));
|
(unsigned long)sizes.text_ra));
|
DTRACE(htab, ("data map - base=0x%lx bound=0x%lx-1 ra=0x%lx\n",
|
DTRACE(htab, ("data map - base=0x%lx bound=0x%lx-1 ra=0x%lx\n",
|
(unsigned long)sizes.data_base,
|
(unsigned long)sizes.data_base,
|
(unsigned long)sizes.data_bound,
|
(unsigned long)sizes.data_bound,
|
(unsigned long)sizes.data_ra));
|
(unsigned long)sizes.data_ra));
|
|
|
/* check for and fix a botched image (text and data segments
|
/* check for and fix a botched image (text and data segments
|
overlap) */
|
overlap) */
|
if ((sizes.text_base <= sizes.data_base
|
if ((sizes.text_base <= sizes.data_base
|
&& sizes.text_bound >= sizes.data_bound)
|
&& sizes.text_bound >= sizes.data_bound)
|
|| (sizes.data_base <= sizes.text_base
|
|| (sizes.data_base <= sizes.text_base
|
&& sizes.data_bound >= sizes.data_bound)
|
&& sizes.data_bound >= sizes.data_bound)
|
|| (sizes.text_bound > sizes.data_base
|
|| (sizes.text_bound > sizes.data_base
|
&& sizes.text_bound <= sizes.data_bound)
|
&& sizes.text_bound <= sizes.data_bound)
|
|| (sizes.text_base >= sizes.data_base
|
|| (sizes.text_base >= sizes.data_base
|
&& sizes.text_base < sizes.data_bound)) {
|
&& sizes.text_base < sizes.data_bound)) {
|
DTRACE(htab, ("text and data segment overlaped - using just data segment\n"));
|
DTRACE(htab, ("text and data segment overlaped - using just data segment\n"));
|
/* check va->ra linear */
|
/* check va->ra linear */
|
if ((sizes.text_base - sizes.text_ra)
|
if ((sizes.text_base - sizes.text_ra)
|
!= (sizes.data_base - sizes.data_ra))
|
!= (sizes.data_base - sizes.data_ra))
|
device_error(me, "overlapping but missaligned text and data segments");
|
device_error(me, "overlapping but missaligned text and data segments");
|
/* enlarge the data segment */
|
/* enlarge the data segment */
|
if (sizes.text_base < sizes.data_base)
|
if (sizes.text_base < sizes.data_base)
|
sizes.data_base = sizes.text_base;
|
sizes.data_base = sizes.text_base;
|
if (sizes.text_bound > sizes.data_bound)
|
if (sizes.text_bound > sizes.data_bound)
|
sizes.data_bound = sizes.text_bound;
|
sizes.data_bound = sizes.text_bound;
|
if (sizes.text_ra < sizes.data_ra)
|
if (sizes.text_ra < sizes.data_ra)
|
sizes.data_ra = sizes.text_ra;
|
sizes.data_ra = sizes.text_ra;
|
/* zap the text segment */
|
/* zap the text segment */
|
sizes.text_base = 0;
|
sizes.text_base = 0;
|
sizes.text_bound = 0;
|
sizes.text_bound = 0;
|
sizes.text_ra = 0;
|
sizes.text_ra = 0;
|
DTRACE(htab, ("common map - base=0x%lx bound=0x%lx-1 ra=0x%lx\n",
|
DTRACE(htab, ("common map - base=0x%lx bound=0x%lx-1 ra=0x%lx\n",
|
(unsigned long)sizes.data_base,
|
(unsigned long)sizes.data_base,
|
(unsigned long)sizes.data_bound,
|
(unsigned long)sizes.data_bound,
|
(unsigned long)sizes.data_ra));
|
(unsigned long)sizes.data_ra));
|
}
|
}
|
|
|
/* set up virtual memory maps for each of the regions */
|
/* set up virtual memory maps for each of the regions */
|
htab_map_region(me, memory, sizes.text_ra, sizes.text_base,
|
htab_map_region(me, memory, sizes.text_ra, sizes.text_base,
|
sizes.text_bound - sizes.text_base,
|
sizes.text_bound - sizes.text_base,
|
wimg, pp,
|
wimg, pp,
|
htaborg, htabmask);
|
htaborg, htabmask);
|
|
|
htab_map_region(me, memory, sizes.data_ra, sizes.data_base,
|
htab_map_region(me, memory, sizes.data_ra, sizes.data_base,
|
sizes.data_bound - sizes.data_base,
|
sizes.data_bound - sizes.data_base,
|
wimg, pp,
|
wimg, pp,
|
htaborg, htabmask);
|
htaborg, htabmask);
|
|
|
/* dma the sections into physical memory */
|
/* dma the sections into physical memory */
|
bfd_map_over_sections (image, htab_dma_binary, (PTR) &sizes);
|
bfd_map_over_sections (image, htab_dma_binary, (PTR) &sizes);
|
}
|
}
|
|
|
static void
|
static void
|
htab_init_data_callback(device *me)
|
htab_init_data_callback(device *me)
|
{
|
{
|
device_instance *memory = NULL;
|
device_instance *memory = NULL;
|
if (WITH_TARGET_WORD_BITSIZE != 32)
|
if (WITH_TARGET_WORD_BITSIZE != 32)
|
device_error(me, "only 32bit targets currently suported");
|
device_error(me, "only 32bit targets currently suported");
|
|
|
/* find memory device */
|
/* find memory device */
|
if (device_find_property(me, "claim") != NULL)
|
if (device_find_property(me, "claim") != NULL)
|
memory = tree_find_ihandle_property(me, "/chosen/memory");
|
memory = tree_find_ihandle_property(me, "/chosen/memory");
|
|
|
/* for the htab, just allocate space for it */
|
/* for the htab, just allocate space for it */
|
if (strcmp(device_name(me), "htab") == 0) {
|
if (strcmp(device_name(me), "htab") == 0) {
|
unsigned_word address = device_find_integer_property(me, "real-address");
|
unsigned_word address = device_find_integer_property(me, "real-address");
|
unsigned_word length = device_find_integer_property(me, "nr-bytes");
|
unsigned_word length = device_find_integer_property(me, "nr-bytes");
|
unsigned_word base = claim_memory(me, memory, address, length);
|
unsigned_word base = claim_memory(me, memory, address, length);
|
if (base == -1 || base != address)
|
if (base == -1 || base != address)
|
device_error(me, "cannot allocate hash table");
|
device_error(me, "cannot allocate hash table");
|
}
|
}
|
|
|
/* for the pte, do all the real work */
|
/* for the pte, do all the real work */
|
if (strcmp(device_name(me), "pte") == 0) {
|
if (strcmp(device_name(me), "pte") == 0) {
|
unsigned32 htaborg;
|
unsigned32 htaborg;
|
unsigned32 htabmask;
|
unsigned32 htabmask;
|
|
|
htab_decode_hash_table(me, &htaborg, &htabmask);
|
htab_decode_hash_table(me, &htaborg, &htabmask);
|
|
|
if (device_find_property(me, "file-name") != NULL) {
|
if (device_find_property(me, "file-name") != NULL) {
|
/* map in a binary */
|
/* map in a binary */
|
unsigned pte_wimg = device_find_integer_property(me, "wimg");
|
unsigned pte_wimg = device_find_integer_property(me, "wimg");
|
unsigned pte_pp = device_find_integer_property(me, "pp");
|
unsigned pte_pp = device_find_integer_property(me, "pp");
|
const char *file_name = device_find_string_property(me, "file-name");
|
const char *file_name = device_find_string_property(me, "file-name");
|
if (device_find_property(me, "real-address") != NULL) {
|
if (device_find_property(me, "real-address") != NULL) {
|
unsigned32 pte_ra = device_find_integer_property(me, "real-address");
|
unsigned32 pte_ra = device_find_integer_property(me, "real-address");
|
DTRACE(htab, ("pte - ra=0x%lx, wimg=%ld, pp=%ld, file-name=%s\n",
|
DTRACE(htab, ("pte - ra=0x%lx, wimg=%ld, pp=%ld, file-name=%s\n",
|
(unsigned long)pte_ra,
|
(unsigned long)pte_ra,
|
(unsigned long)pte_wimg,
|
(unsigned long)pte_wimg,
|
(long)pte_pp,
|
(long)pte_pp,
|
file_name));
|
file_name));
|
htab_map_binary(me, memory, pte_ra, pte_wimg, pte_pp, file_name,
|
htab_map_binary(me, memory, pte_ra, pte_wimg, pte_pp, file_name,
|
htaborg, htabmask);
|
htaborg, htabmask);
|
}
|
}
|
else {
|
else {
|
DTRACE(htab, ("pte - wimg=%ld, pp=%ld, file-name=%s\n",
|
DTRACE(htab, ("pte - wimg=%ld, pp=%ld, file-name=%s\n",
|
(unsigned long)pte_wimg,
|
(unsigned long)pte_wimg,
|
(long)pte_pp,
|
(long)pte_pp,
|
file_name));
|
file_name));
|
htab_map_binary(me, memory, -1, pte_wimg, pte_pp, file_name,
|
htab_map_binary(me, memory, -1, pte_wimg, pte_pp, file_name,
|
htaborg, htabmask);
|
htaborg, htabmask);
|
}
|
}
|
}
|
}
|
else {
|
else {
|
/* handle a normal mapping definition */
|
/* handle a normal mapping definition */
|
unsigned64 pte_va = 0;
|
unsigned64 pte_va = 0;
|
unsigned32 pte_ra = device_find_integer_property(me, "real-address");
|
unsigned32 pte_ra = device_find_integer_property(me, "real-address");
|
unsigned pte_nr_bytes = device_find_integer_property(me, "nr-bytes");
|
unsigned pte_nr_bytes = device_find_integer_property(me, "nr-bytes");
|
unsigned pte_wimg = device_find_integer_property(me, "wimg");
|
unsigned pte_wimg = device_find_integer_property(me, "wimg");
|
unsigned pte_pp = device_find_integer_property(me, "pp");
|
unsigned pte_pp = device_find_integer_property(me, "pp");
|
signed_cell partial_va;
|
signed_cell partial_va;
|
int i;
|
int i;
|
for (i = 0;
|
for (i = 0;
|
device_find_integer_array_property(me, "virtual-address", i, &partial_va);
|
device_find_integer_array_property(me, "virtual-address", i, &partial_va);
|
i++) {
|
i++) {
|
pte_va = (pte_va << WITH_TARGET_WORD_BITSIZE) | (unsigned_cell)partial_va;
|
pte_va = (pte_va << WITH_TARGET_WORD_BITSIZE) | (unsigned_cell)partial_va;
|
}
|
}
|
DTRACE(htab, ("pte - ra=0x%lx, wimg=%ld, pp=%ld, va=0x%lx, nr_bytes=%ld\n",
|
DTRACE(htab, ("pte - ra=0x%lx, wimg=%ld, pp=%ld, va=0x%lx, nr_bytes=%ld\n",
|
(unsigned long)pte_ra,
|
(unsigned long)pte_ra,
|
(long)pte_wimg,
|
(long)pte_wimg,
|
(long)pte_pp,
|
(long)pte_pp,
|
(unsigned long)pte_va,
|
(unsigned long)pte_va,
|
(long)pte_nr_bytes));
|
(long)pte_nr_bytes));
|
htab_map_region(me, memory, pte_ra, pte_va, pte_nr_bytes, pte_wimg, pte_pp,
|
htab_map_region(me, memory, pte_ra, pte_va, pte_nr_bytes, pte_wimg, pte_pp,
|
htaborg, htabmask);
|
htaborg, htabmask);
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
|
|
static device_callbacks const htab_callbacks = {
|
static device_callbacks const htab_callbacks = {
|
{ NULL, htab_init_data_callback, },
|
{ NULL, htab_init_data_callback, },
|
{ NULL, }, /* address */
|
{ NULL, }, /* address */
|
{ NULL, }, /* IO */
|
{ NULL, }, /* IO */
|
{ passthrough_device_dma_read_buffer,
|
{ passthrough_device_dma_read_buffer,
|
passthrough_device_dma_write_buffer, },
|
passthrough_device_dma_write_buffer, },
|
{ NULL, }, /* interrupt */
|
{ NULL, }, /* interrupt */
|
{ generic_device_unit_decode,
|
{ generic_device_unit_decode,
|
generic_device_unit_encode, },
|
generic_device_unit_encode, },
|
};
|
};
|
|
|
const device_descriptor hw_htab_device_descriptor[] = {
|
const device_descriptor hw_htab_device_descriptor[] = {
|
{ "htab", NULL, &htab_callbacks },
|
{ "htab", NULL, &htab_callbacks },
|
{ "pte", NULL, &htab_callbacks }, /* yep - uses htab's table */
|
{ "pte", NULL, &htab_callbacks }, /* yep - uses htab's table */
|
{ NULL },
|
{ NULL },
|
};
|
};
|
|
|
#endif /* _HW_HTAB_C_ */
|
#endif /* _HW_HTAB_C_ */
|
|
|