Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,11 +217,15 @@ is also what lets detection survive a kernel that will not hand over

Ambarella (`src/hal/ambarella.c`) stops at the machine string on purpose. The
exact part (S3L33M, S3L55M, S3L66, ...) is a word the DSP firmware writes,
reachable only through `/dev/iav`, so the report says `S3L`. Total RAM is the
reachable only through `/dev/iav`, so the report says `S3L`, plus `family: S3Lm`
when `iav.ko` is loaded. Total RAM is the
top of the DSP carve-out, because `mem=` keeps the kernel far below it: 118 MiB
of 512 MiB on the camera in #266, where the DRAM marking confirmed the figure.
The carve-out comes from `/proc/device-tree/iavmem/reg`, or from the boot log's
`IAVMEM` line on kernels with no `/proc/device-tree`, which Dahua's 3.10.73 is.
Only its end is trusted: Hikvision's kernel moves the split at boot and leaves
`/iavmem` stale, so media is what lies above Linux's RAM in `/proc/iomem`, and
with no such RAM listed it is left out, not guessed.
That line is printed once, so if the ring buffer has dropped it the report falls
back to what the kernel sees. Stock Dahua firmware has no `/dev/i2c-*` either:
its own `sensor.ko` owns the bus, so no sensor is reported there, and reaching
Expand Down
56 changes: 52 additions & 4 deletions src/hal/ambarella.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@
/* Defaults of the `addr` module parameter across the S3L SDK's VIN drivers,
* the 8-bit form ipctool's tables use. AR0521 is the one part left out: it
* answers on 0x6C, and the onsemi probe runs before the OmniVision one, so
* listing it would have that probe reading an OV4689. */
* listing it would have that probe reading an OV4689. 0x30 is not a default:
* the Hikvision DS-2CD2423G0-I strings its AR0237 there. */
static unsigned char sony_addrs[] = {0x34, 0};
static unsigned char onsemi_addrs[] = {0x20, 0};
static unsigned char onsemi_addrs[] = {0x20, 0x30, 0};
static unsigned char omni_addrs[] = {0x6c, 0};

static sensor_addr_t ambarella_possible_i2c_addrs[] = {
Expand Down Expand Up @@ -88,6 +89,52 @@ bool ambarella_iavmem_from_log(const char *log, uint32_t *start,
end == '\n';
}

/* The carve-out's end is the top of DRAM on every board seen, but its start
* cannot be trusted: Hikvision's kernel moves the split at boot, and leaves
* /iavmem saying 0x04000000 where it gave Linux up to 0x07000000. So media is
* what lies between the top of Linux's RAM and that end, and with no RAM listed
* to measure from it is unknown: 0, which the report leaves out. */
unsigned long ambarella_media_kb(const char *iomem, uint64_t end) {
FILE *f = fopen(iomem, "r");
uint64_t top = 0;
char line[128];

if (!f)
return 0;

/* Top level only: "Kernel code" and the like are indented inside it,
* and %llx would skip that indent */
while (fgets(line, sizeof(line), f)) {
unsigned long long from, to;
int name = 0;

if (*line != ' ' &&
sscanf(line, "%llx-%llx : %n", &from, &to, &name) == 2 && name &&
!strncmp(line + name, "System RAM", 10) && to + 1 > top)
top = to + 1;
}
fclose(f);

return top && top < end ? (end - top) / 1024 : 0;
}

/* iav's own view of the part, there once iav.ko is loaded: "S3Lm", which the
* machine string cannot tell from S3L. */
bool ambarella_family(const char *iav, char *out, size_t outlen) {
if (!outlen || !line_from_file(iav, "AMBARELLA_CHIP=(\\w+)", out, outlen))
return false;

out[outlen - 1] = '\0';
return true;
}

static void ambarella_chip_properties(cJSON *j_inner) {
char family[32];

if (ambarella_family("/proc/ambarella/iav", family, sizeof(family)))
ADD_PARAM("family", family);
}

static unsigned long ambarella_totalmem(unsigned long *media_mem) {
uint32_t start = 0, size = 0;
bool found = ambarella_iavmem_from_dt("/proc/device-tree/iavmem/reg",
Expand All @@ -113,14 +160,15 @@ static unsigned long ambarella_totalmem(unsigned long *media_mem) {
if (!found || !size || start + size < start)
return kernel_mem();

*media_mem = size / 1024;
return (unsigned long)(start / 1024) + *media_mem;
*media_mem = ambarella_media_kb("/proc/iomem", (uint64_t)start + size);
return (unsigned long)(((uint64_t)start + size) / 1024);
}
#endif

void ambarella_setup_hal() {
possible_i2c_addrs = ambarella_possible_i2c_addrs;
#ifndef STANDALONE_LIBRARY
hal_totalmem = ambarella_totalmem;
hal_chip_properties = ambarella_chip_properties;
#endif
}
2 changes: 2 additions & 0 deletions src/hal/ambarella.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,7 @@ bool ambarella_iavmem_from_dt(const char *path, uint32_t *start,
uint32_t *size);
bool ambarella_iavmem_from_log(const char *log, uint32_t *start,
uint32_t *size);
unsigned long ambarella_media_kb(const char *iomem, uint64_t end);
bool ambarella_family(const char *iav, char *out, size_t outlen);

#endif /* HAL_AMBARELLA_H */
60 changes: 60 additions & 0 deletions src/hal/ambarella_test.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* Hardware-free cover for the Ambarella machine-string parser. The strings
* are the DT_MACHINE_START names in the vendor kernel, and the S3L cpuinfo is
* the one from issue #266. */
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
Expand Down Expand Up @@ -101,6 +102,65 @@ int main() {
CHECK(rounded_num(513) == 1024);
CHECK(rounded_num(1) == 1);

/* Two boards. On the DS-2CD2423G0-I /iavmem is stale: the DT says the
* DSP starts at 64 MiB and Linux runs to 112 MiB. On the IP4M-1026E the
* two agree, Linux ending exactly where the DSP starts. */
{
char iomem[] = "/tmp/ambarella_test.XXXXXX";
const char *hik = "00200000-06ffffff : System RAM\n"
" 00208000-00719667 : Kernel code\n";
const char *dahua = "00200000-077fffff : System RAM\n";
/* Split, the higher range last, and an indented line that must not
* count however high it goes */
const char *split = "00200000-03ffffff : System RAM\n"
" 00208000-00719667 : Kernel code\n"
"04100000-06ffffff : System RAM\n"
" 0ff00000-0fffffff : System RAM\n";
const char *none = "e8005000-e8005fff : uart\n";
const uint64_t top = 0x10000000;
int ifd = mkstemp(iomem);

CHECK(ifd >= 0);
close(ifd);
#define IOMEM(text) \
do { \
int w = open(iomem, O_WRONLY | O_TRUNC); \
CHECK(w >= 0); \
CHECK(write(w, text, strlen(text)) == (ssize_t)strlen(text)); \
close(w); \
} while (0)
IOMEM(hik);
CHECK(ambarella_media_kb(iomem, top) == 144 * 1024);
IOMEM(dahua);
CHECK(ambarella_media_kb(iomem, 0x20000000) == 392 * 1024);
IOMEM(split);
CHECK(ambarella_media_kb(iomem, top) == 144 * 1024);

/* Nothing to measure from, or Linux past the end: unknown */
IOMEM(none);
CHECK(ambarella_media_kb(iomem, top) == 0);
IOMEM(hik);
CHECK(ambarella_media_kb(iomem, 0x07000000) == 0);
unlink(iomem);
CHECK(ambarella_media_kb(iomem, top) == 0);
#undef IOMEM
}

{
char iav[] = "/tmp/ambarella_test.XXXXXX";
const char *text = "AMBARELLA_CHIP=S3Lm\ndsp_op_mode: 1\n";
char family[16];
int ifd = mkstemp(iav);

CHECK(ifd >= 0);
CHECK(write(ifd, text, strlen(text)) == (ssize_t)strlen(text));
close(ifd);
CHECK(ambarella_family(iav, family, sizeof(family)));
CHECK(!strcmp(family, "S3Lm"));
unlink(iav);
CHECK(!ambarella_family(iav, family, sizeof(family)));
}

if (failures)
return EXIT_FAILURE;
puts("ambarella_test: all cases passed");
Expand Down
6 changes: 6 additions & 0 deletions src/sensors.c
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,12 @@ static int detect_onsemi_sensor(sensor_ctx_t *ctx, int fd,
case 0x256:
sid = 0x0237;
break;
/* Register 0x3000 reads 0x0950 on the DS-2CD2423G0-I, whose firmware
* drives that sensor with its ar0237 module. No datasheet to hand: the
* vendor driver reads this register but does not check it. */
case 0x5009:
sid = 0x0237;
break;
case 0x2602:
sid = 0x0331;
break;
Expand Down
1 change: 1 addition & 0 deletions src/sensors_golden.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1102,6 +1102,7 @@ onsemi 0256 AR0237
onsemi 2402 AR0130
onsemi 2602 AR0331
onsemi 2604 AR0330
onsemi 5009 AR0237
omni 2710 OV2710
omni 2715 OV2715
omni 2718 OV2718
Expand Down
Loading