Changeset View
Standalone View
sys/kern/subr_physmem.c
Show All 34 Lines | ||||||||||
#endif | #endif | |||||||||
/* | /* | |||||||||
* Routines for describing and initializing anything related to physical memory. | * Routines for describing and initializing anything related to physical memory. | |||||||||
*/ | */ | |||||||||
#include <sys/param.h> | #include <sys/param.h> | |||||||||
#include <sys/systm.h> | #include <sys/systm.h> | |||||||||
#include <sys/bus.h> | ||||||||||
#include <sys/kernel.h> | #include <sys/kernel.h> | |||||||||
#include <sys/module.h> | ||||||||||
#include <sys/physmem.h> | #include <sys/physmem.h> | |||||||||
#ifdef _KERNEL | #ifdef _KERNEL | |||||||||
#include <vm/vm.h> | #include <vm/vm.h> | |||||||||
#include <vm/vm_param.h> | #include <vm/vm_param.h> | |||||||||
#include <vm/vm_page.h> | #include <vm/vm_page.h> | |||||||||
#include <vm/vm_phys.h> | #include <vm/vm_phys.h> | |||||||||
#include <vm/vm_dumpset.h> | #include <vm/vm_dumpset.h> | |||||||||
#include <machine/md_var.h> | #include <machine/md_var.h> | |||||||||
#include <machine/resource.h> | ||||||||||
#else | #else | |||||||||
#include <stdarg.h> | #include <stdarg.h> | |||||||||
#include <stdio.h> | #include <stdio.h> | |||||||||
#include <string.h> | #include <string.h> | |||||||||
#endif | #endif | |||||||||
/* | /* | |||||||||
* These structures are used internally to keep track of regions of physical | * These structures are used internally to keep track of regions of physical | |||||||||
▲ Show 20 Lines • Show All 456 Lines • ▼ Show 20 Lines | ||||||||||
DB_SHOW_COMMAND_FLAGS(physmem, db_show_physmem, DB_CMD_MEMSAFE) | DB_SHOW_COMMAND_FLAGS(physmem, db_show_physmem, DB_CMD_MEMSAFE) | |||||||||
{ | { | |||||||||
physmem_dump_tables(db_printf); | physmem_dump_tables(db_printf); | |||||||||
} | } | |||||||||
#endif /* DDB */ | #endif /* DDB */ | |||||||||
ehem_freebsd_m5p.comUnsubmitted Done Inline Actions
ehem_freebsd_m5p.com: | ||||||||||
#ifdef _KERNEL | ||||||||||
/* | ||||||||||
* ram pseudo driver - this reserves memory resources corresponding to physical | ||||||||||
* memory regions. | ||||||||||
*/ | ||||||||||
static void | ||||||||||
ram_identify(driver_t *driver, device_t parent) | ||||||||||
{ | ||||||||||
if (resource_disabled("ram", 0)) | ||||||||||
return; | ||||||||||
if (BUS_ADD_CHILD(parent, 0, "ram", 0) == NULL) | ||||||||||
panic("ram_identify"); | ||||||||||
} | ||||||||||
static int | ||||||||||
ram_probe(device_t dev) | ||||||||||
{ | ||||||||||
device_quiet(dev); | ||||||||||
device_set_desc(dev, "System RAM"); | ||||||||||
return (BUS_PROBE_SPECIFIC); | ||||||||||
} | ||||||||||
static int | ||||||||||
ram_attach(device_t dev) | ||||||||||
{ | ||||||||||
vm_paddr_t avail_list[PHYS_AVAIL_COUNT]; | ||||||||||
rman_res_t start, end; | ||||||||||
struct region *hwp; | ||||||||||
int rid, i; | ||||||||||
rid = 0; | ||||||||||
/* Get the avail list. */ | ||||||||||
bzero(avail_list, sizeof(avail_list)); | ||||||||||
regions_to_avail(avail_list, EXFLAG_NOALLOC | EXFLAG_NODUMP, | ||||||||||
PHYS_AVAIL_COUNT, 0, NULL, NULL); | ||||||||||
/* Reserve all memory regions. */ | ||||||||||
for (i = 0; avail_list[i + 1] != 0; i += 2) { | ||||||||||
start = avail_list[i]; | ||||||||||
end = avail_list[i + 1]; | ||||||||||
if (bootverbose) | ||||||||||
device_printf(dev, | ||||||||||
"reserving memory region: %jx-%jx\n", | ||||||||||
(uintmax_t)start, (uintmax_t)end); | ||||||||||
if (bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, start, end, | ||||||||||
end - start, 0) == NULL) | ||||||||||
panic("ram_attach: resource %d failed to attach", rid); | ||||||||||
rid++; | ||||||||||
} | ||||||||||
/* Now, reserve the excluded memory regions. */ | ||||||||||
for (i = 0, hwp = exregions; i < excnt; i++, hwp++) { | ||||||||||
start = hwp->addr; | ||||||||||
end = hwp->addr + hwp->size; | ||||||||||
if (bootverbose) | ||||||||||
device_printf(dev, | ||||||||||
"reserving excluded region: %jx-%jx\n", | ||||||||||
(uintmax_t)start, (uintmax_t)(end - 1)); | ||||||||||
/* | ||||||||||
* Best-effort attempt to reserve the range. This may fail, as | ||||||||||
* sometimes the excluded ranges provided by the device tree | ||||||||||
* will cover or overlap some I/O range. | ||||||||||
*/ | ||||||||||
if (bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, start, end, | ||||||||||
impUnsubmitted Done Inline ActionsHow would the interact with a device that's pre-programmed at boot to use certain parts of memory that are in the reserved range? If ram0 attaches first, how will it affect that? Right now, for the code I'm working on, we just use the memory that's in the reserved range and don't bother to allocate it with bus_alloc_resource. Is that the right way to use it? If so, what happens if ram0 runs first? imp: How would the interact with a device that's pre-programmed at boot to use certain parts of… | ||||||||||
ehem_freebsd_m5p.comUnsubmitted Done Inline ActionsI suspect that would be a problem. The device needs to have its range in the device-tree or ACPI, and those subsystems would initially reserve the region for you. Meanwhile I've got the opposite situation. A device which can use pretty well arbitrary regions for mapping, thus needs the nexus to know what address ranges are completely unused so it can allocate a free range. It can use actual memory ranges just fine, but that causes usable memory to disappear. You may need to commandeer this diff to fix the issue. ehem_freebsd_m5p.com: I suspect that would be a problem. The device needs to have its range in the device-tree or… | ||||||||||
impUnsubmitted Done Inline ActionsThese ranges are definitely not in ACPI/FDT. When linux kexec's an arm64 kernel, the gic is up and running. There's no way to reprogram it, so we have to re-use the memory that Linux used to get it started. This data is kludged-passed to us in the UEFI tables (I have code that adds the reserved ranges here, and also queries that memory we find programmed into this device are in the reserved ranges not yet committed). It's possible to add an additional flag to my calls 'really really reserved, don't nobody else use it ever' flag since the memory is added to this in one place. That might be another way to deal with my F@^^ up bug workaround... imp: These ranges are definitely not in ACPI/FDT. When linux kexec's an arm64 kernel, the gic is up… | ||||||||||
mhorneAuthorUnsubmitted Done Inline Actions@imp so, let me make sure I understand. These reserved ranges correspond to real physical memory, and the GIC driver will be taught to locate these ranges, map them into KVA, and use them? If this is the case, I don't think this change will affect your work, and you are using those reserved ranges correctly. The ram pseudo driver is just to help with the I/O space bookkeeping. "Real" memory is conceptually a totally different type of resource, and is not managed with the bus_*() APIs, but rather physmem, uma, malloc, etc. It just so happens that real memory, as a whole, consumes some of the resource that is SYS_RES_MEMORY, and we need to capture that somewhere. Put differently, why would any driver call bus_alloc_resource() for real memory? In the typical case of allocating memory through malloc(9), it does not reserve the underlying physical range(s) of I/O space in this way. mhorne: @imp so, let me make sure I understand. These reserved ranges correspond to real physical… | ||||||||||
impUnsubmitted Done Inline ActionsYes. The memory is marked as reserved by some funky means that's not yet in the tree, so would wind up being allocated by the ram driver. So in that case, we'd advise driver writers not to bus_alloc_resource the memory. The memory so marked in the linux tables is memory that can't be used except by the device(s) that are already using it. So it would be up to the device writer to know this, discover this and use this memory. In that case, this driver wouldn't create an issue and it wouldn't interfere with my work, nor would changes be needed to my work. I like that result, and the rule is clear enough to explain. 'malloc' manages DRAM for non-reserved areas, and some architecture / model dependent code knows how to (a) discover the memory and (b) check that it's properly reserved as it expects using means other than bus_alloc_resources. imp: Yes. The memory is marked as reserved by some funky means that's not yet in the tree, so would… | ||||||||||
end - start, 0) == NULL) { | ||||||||||
if (bootverbose) | ||||||||||
device_printf(dev, "failed to reserve region\n"); | ||||||||||
continue; | ||||||||||
} | ||||||||||
rid++; | ||||||||||
} | ||||||||||
return (0); | ||||||||||
} | ||||||||||
static device_method_t ram_methods[] = { | ||||||||||
/* Device interface */ | ||||||||||
DEVMETHOD(device_identify, ram_identify), | ||||||||||
DEVMETHOD(device_probe, ram_probe), | ||||||||||
DEVMETHOD(device_attach, ram_attach), | ||||||||||
DEVMETHOD_END | ||||||||||
}; | ||||||||||
DEFINE_CLASS_0(ram, ram_driver, ram_methods, /* no softc */ 1); | ||||||||||
DRIVER_MODULE(ram, nexus, ram_driver, 0, 0); | ||||||||||
Done Inline Actions
ehem_freebsd_m5p.com: | ||||||||||
Done Inline ActionsNow appear to need to nuke ram_devclass then remove the ram_devclass argument from DRIVER_MODULE(). ehem_freebsd_m5p.com: Now appear to need to nuke `ram_devclass` then remove the `ram_devclass` argument from… | ||||||||||
#endif /* _KERNEL */ |