James Molloy
2008-06-09 08:29:33 UTC
/Apologies for the possible repost - I checked the mailing list archives
and my message didn't seem to appear, so I've now subscribed to the
mailing list to check if it does./
Hi,
I'm using PearPC to assist me in developing a hobby OS for the PowerPC
platform (in addition to real hardware) and noticed that PearPC doesn't
expose the "translations" property of the MMU firmware device node.
The translations property is documented in the OpenBios PowerPC bindings
document and is aimed at helping the client program replicate the HTAB
before taking full control of memory management. I took the liberty of
creating this property myself.
As far as I can tell, PearPC doesn't maintain an explicit list of
mmu->map() calls, so my algorithm searches the HTAB for every page in
the effective address space and manually constructs a list of them. It's
O(n), but since it's only intended to be called twice (once from the
getproplen call and once from the getprop call) I don't see that as much
of a handicap. It executes seemingly instantaneously on my Core2Duo
running the x86_64 JITC cpu.
Anyway, let me know if it's not up to coding standard or there are too
few comments and I'll change them.
Cheers,
James Molloy
Index: src/io/prom/promdt.cc
==============================
=====================================
RCS file: /cvsroot/pearpc/pearpc/src/io/prom/promdt.cc,v
retrieving revision 1.29
diff -u -r1.29 promdt.cc
--- src/io/prom/promdt.cc 16 Aug 2005 12:26:43 -0000 1.29
+++ src/io/prom/promdt.cc 8 Jun 2008 09:48:24 -0000
@@ -1032,6 +1032,95 @@
}
}
+/*
+ * PromPropMMU: Implements the MMU's "translations" property, which allows
+ * client programs to replicate the HTAB contents before taking over
+ * memory management.
+ */
+PromPropMMU::PromPropMMU(const char *aName)
+ :PromProp(aName), nValidTranslations(0)
+{
+}
+
+PromPropMMU::~PromPropMMU()
+{
+}
+
+uint32 PromPropMMU::getValueLen()
+{
+ calculateTranslations();
+ return nValidTranslations*sizeof(Translation);
+}
+
+uint32 PromPropMMU::getValue(uint32 buf, uint32 buflen)
+{
+ calculateTranslations();
+ if (nValidTranslations*sizeof(Translation) < buflen)
+ {
+ buflen = nValidTranslations*sizeof(Translation);
+ }
+
+ // Convert all values to BE.
+ for (int i = 0; i < nValidTranslations; i++)
+ {
+ translations[i].virt = ppc_word_to_BE(translations[i].virt);
+ translations[i].phys = ppc_word_to_BE(translations[i].phys);
+ translations[i].size = ppc_word_to_BE(translations[i].size);
+ translations[i].mode = ppc_word_to_BE(translations[i].mode);
+ }
+
+ uint32 phys;
+ ppc_prom_effective_to_physical(phys, buf);
+ ppc_dma_write(phys, (void*)translations, buflen);
+ return 0;
+}
+
+uint32 PromPropMMU::setValue(uint32 buf, uint32 buflen)
+{
+ return -1;
+}
+
+void PromPropMMU::calculateTranslations()
+{
+ nValidTranslations = 0;
+ uint32 phys;
+ // For every page in the address space, check for a mapping.
+ for (uint32 i = 0; i <= 0xFFFFF; i++)
+ {
+ uint32 ea = i << 12;
+ if (ppc_prom_effective_to_physical(phys, ea))
+ {
+ // A valid translation exists. Add to the translations list.
+ addTranslation(ea, phys);
+ }
+ }
+}
+
+void PromPropMMU::addTranslation(uint32 ea, uint32 phys)
+{
+ // Can the given translation be appended to translation
'nValidTranslations-1'?
+ if ( (nValidTranslations > 0) &&
+ (translations[nValidTranslations-1].virt +
translations[nValidTranslations-1].size == ea) &&
+ (translations[nValidTranslations-1].phys +
translations[nValidTranslations-1].size == phys) )
+ {
+ // Modify 'nValidTranslations'.
+ translations[nValidTranslations-1].size += 0x1000;
+ }
+ else
+ {
+ // Else add a new translation.
+ translations[nValidTranslations].virt = ea;
+ translations[nValidTranslations].phys = phys;
+ translations[nValidTranslations].size = 0x1000;
+ translations[nValidTranslations].mode = 0x6a;
+ nValidTranslations++;
+ if (nValidTranslations == NUM_TRANSLATIONS)
+ {
+ IO_PROM_ERR("PromPropMMU::calculateTranslations - too many
translations.");
+ }
+ }
+}
+
/*******************************************************************************
*
*/
@@ -1111,6 +1200,8 @@
gPromRoot->addNode(cpus);
gPromRoot->addNode(kbd);
+ mmu->addProp(new PromPropMMU("translations"));
+
PromNode *cpu = new PromNode("PowerPC,G4");
cpus->addNode(cpu);
cpus->addProp(new PromPropInt("#size-cells", 0));
Index: src/io/prom/promdt.h
===================================================================
RCS file: /cvsroot/pearpc/pearpc/src/io/prom/promdt.h,v
retrieving revision 1.3
diff -u -r1.3 promdt.h
--- src/io/prom/promdt.h 21 May 2004 22:29:43 -0000 1.3
+++ src/io/prom/promdt.h 8 Jun 2008 09:48:24 -0000
@@ -272,6 +272,30 @@
virtual uint32 setValue(uint32 buf, uint32 buflen);
};
+#define NUM_TRANSLATIONS 256
+class PromPropMMU: public PromProp {
+public:
+ PromPropMMU(const char *name);
+ virtual ~PromPropMMU();
+
+ virtual uint32 getValueLen();
+ virtual uint32 getValue(uint32 buf, uint32 buflen);
+ virtual uint32 setValue(uint32 buf, uint32 buflen);
+
+private:
+ void calculateTranslations();
+ void addTranslation(uint32 ea, uint32 phys);
+ struct Translation
+ {
+ uint32 virt;
+ uint32 size;
+ uint32 phys;
+ uint32 mode;
+ };
+ Translation translations[NUM_TRANSLATIONS];
+ uint32 nValidTranslations;
+};
+
#define FIND_DEVICE_FIND 0
#define FIND_DEVICE_OPEN 1
PromNode *findDevice(const char *aPathName, int type,
PromInstanceHandle *ret);
and my message didn't seem to appear, so I've now subscribed to the
mailing list to check if it does./
Hi,
I'm using PearPC to assist me in developing a hobby OS for the PowerPC
platform (in addition to real hardware) and noticed that PearPC doesn't
expose the "translations" property of the MMU firmware device node.
The translations property is documented in the OpenBios PowerPC bindings
document and is aimed at helping the client program replicate the HTAB
before taking full control of memory management. I took the liberty of
creating this property myself.
As far as I can tell, PearPC doesn't maintain an explicit list of
mmu->map() calls, so my algorithm searches the HTAB for every page in
the effective address space and manually constructs a list of them. It's
O(n), but since it's only intended to be called twice (once from the
getproplen call and once from the getprop call) I don't see that as much
of a handicap. It executes seemingly instantaneously on my Core2Duo
running the x86_64 JITC cpu.
Anyway, let me know if it's not up to coding standard or there are too
few comments and I'll change them.
Cheers,
James Molloy
Index: src/io/prom/promdt.cc
==============================
=====================================
RCS file: /cvsroot/pearpc/pearpc/src/io/prom/promdt.cc,v
retrieving revision 1.29
diff -u -r1.29 promdt.cc
--- src/io/prom/promdt.cc 16 Aug 2005 12:26:43 -0000 1.29
+++ src/io/prom/promdt.cc 8 Jun 2008 09:48:24 -0000
@@ -1032,6 +1032,95 @@
}
}
+/*
+ * PromPropMMU: Implements the MMU's "translations" property, which allows
+ * client programs to replicate the HTAB contents before taking over
+ * memory management.
+ */
+PromPropMMU::PromPropMMU(const char *aName)
+ :PromProp(aName), nValidTranslations(0)
+{
+}
+
+PromPropMMU::~PromPropMMU()
+{
+}
+
+uint32 PromPropMMU::getValueLen()
+{
+ calculateTranslations();
+ return nValidTranslations*sizeof(Translation);
+}
+
+uint32 PromPropMMU::getValue(uint32 buf, uint32 buflen)
+{
+ calculateTranslations();
+ if (nValidTranslations*sizeof(Translation) < buflen)
+ {
+ buflen = nValidTranslations*sizeof(Translation);
+ }
+
+ // Convert all values to BE.
+ for (int i = 0; i < nValidTranslations; i++)
+ {
+ translations[i].virt = ppc_word_to_BE(translations[i].virt);
+ translations[i].phys = ppc_word_to_BE(translations[i].phys);
+ translations[i].size = ppc_word_to_BE(translations[i].size);
+ translations[i].mode = ppc_word_to_BE(translations[i].mode);
+ }
+
+ uint32 phys;
+ ppc_prom_effective_to_physical(phys, buf);
+ ppc_dma_write(phys, (void*)translations, buflen);
+ return 0;
+}
+
+uint32 PromPropMMU::setValue(uint32 buf, uint32 buflen)
+{
+ return -1;
+}
+
+void PromPropMMU::calculateTranslations()
+{
+ nValidTranslations = 0;
+ uint32 phys;
+ // For every page in the address space, check for a mapping.
+ for (uint32 i = 0; i <= 0xFFFFF; i++)
+ {
+ uint32 ea = i << 12;
+ if (ppc_prom_effective_to_physical(phys, ea))
+ {
+ // A valid translation exists. Add to the translations list.
+ addTranslation(ea, phys);
+ }
+ }
+}
+
+void PromPropMMU::addTranslation(uint32 ea, uint32 phys)
+{
+ // Can the given translation be appended to translation
'nValidTranslations-1'?
+ if ( (nValidTranslations > 0) &&
+ (translations[nValidTranslations-1].virt +
translations[nValidTranslations-1].size == ea) &&
+ (translations[nValidTranslations-1].phys +
translations[nValidTranslations-1].size == phys) )
+ {
+ // Modify 'nValidTranslations'.
+ translations[nValidTranslations-1].size += 0x1000;
+ }
+ else
+ {
+ // Else add a new translation.
+ translations[nValidTranslations].virt = ea;
+ translations[nValidTranslations].phys = phys;
+ translations[nValidTranslations].size = 0x1000;
+ translations[nValidTranslations].mode = 0x6a;
+ nValidTranslations++;
+ if (nValidTranslations == NUM_TRANSLATIONS)
+ {
+ IO_PROM_ERR("PromPropMMU::calculateTranslations - too many
translations.");
+ }
+ }
+}
+
/*******************************************************************************
*
*/
@@ -1111,6 +1200,8 @@
gPromRoot->addNode(cpus);
gPromRoot->addNode(kbd);
+ mmu->addProp(new PromPropMMU("translations"));
+
PromNode *cpu = new PromNode("PowerPC,G4");
cpus->addNode(cpu);
cpus->addProp(new PromPropInt("#size-cells", 0));
Index: src/io/prom/promdt.h
===================================================================
RCS file: /cvsroot/pearpc/pearpc/src/io/prom/promdt.h,v
retrieving revision 1.3
diff -u -r1.3 promdt.h
--- src/io/prom/promdt.h 21 May 2004 22:29:43 -0000 1.3
+++ src/io/prom/promdt.h 8 Jun 2008 09:48:24 -0000
@@ -272,6 +272,30 @@
virtual uint32 setValue(uint32 buf, uint32 buflen);
};
+#define NUM_TRANSLATIONS 256
+class PromPropMMU: public PromProp {
+public:
+ PromPropMMU(const char *name);
+ virtual ~PromPropMMU();
+
+ virtual uint32 getValueLen();
+ virtual uint32 getValue(uint32 buf, uint32 buflen);
+ virtual uint32 setValue(uint32 buf, uint32 buflen);
+
+private:
+ void calculateTranslations();
+ void addTranslation(uint32 ea, uint32 phys);
+ struct Translation
+ {
+ uint32 virt;
+ uint32 size;
+ uint32 phys;
+ uint32 mode;
+ };
+ Translation translations[NUM_TRANSLATIONS];
+ uint32 nValidTranslations;
+};
+
#define FIND_DEVICE_FIND 0
#define FIND_DEVICE_OPEN 1
PromNode *findDevice(const char *aPathName, int type,
PromInstanceHandle *ret);