mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-11-10 09:44:13 +00:00
dcp/parser: Add parser from linux DCP required for parsing dcp AFK/EPIC
Signed-off-by: Janne Grunau <j@jannau.net>
This commit is contained in:
parent
4cb3dceb0a
commit
02cedf3f45
3 changed files with 297 additions and 2 deletions
8
Makefile
8
Makefile
|
@ -73,6 +73,9 @@ LIBFDT_OBJECTS := $(patsubst %,libfdt/%, \
|
||||||
fdt_addresses.o fdt_empty_tree.o fdt_ro.o fdt_rw.o fdt_strerror.o fdt_sw.o \
|
fdt_addresses.o fdt_empty_tree.o fdt_ro.o fdt_rw.o fdt_strerror.o fdt_sw.o \
|
||||||
fdt_wip.o fdt.o)
|
fdt_wip.o fdt.o)
|
||||||
|
|
||||||
|
DCP_OBJECTS := $(patsubst %,dcp/%, \
|
||||||
|
parser.o)
|
||||||
|
|
||||||
OBJECTS := \
|
OBJECTS := \
|
||||||
adt.o \
|
adt.o \
|
||||||
afk.o \
|
afk.o \
|
||||||
|
@ -129,6 +132,7 @@ OBJECTS := \
|
||||||
utils.o utils_asm.o \
|
utils.o utils_asm.o \
|
||||||
vsprintf.o \
|
vsprintf.o \
|
||||||
wdt.o \
|
wdt.o \
|
||||||
|
$(DCP_OBJECTS) \
|
||||||
$(MINILZLIB_OBJECTS) $(TINF_OBJECTS) $(DLMALLOC_OBJECTS) $(LIBFDT_OBJECTS) $(RUST_LIBS)
|
$(MINILZLIB_OBJECTS) $(TINF_OBJECTS) $(DLMALLOC_OBJECTS) $(LIBFDT_OBJECTS) $(RUST_LIBS)
|
||||||
|
|
||||||
FP_OBJECTS := \
|
FP_OBJECTS := \
|
||||||
|
@ -152,9 +156,9 @@ all: update_tag update_cfg build/$(TARGET) build/$(TARGET_RAW)
|
||||||
clean:
|
clean:
|
||||||
rm -rf build/*
|
rm -rf build/*
|
||||||
format:
|
format:
|
||||||
$(CLANG_FORMAT) -i src/*.c src/math/*.c src/*.h src/math/*.h sysinc/*.h
|
$(CLANG_FORMAT) -i src/*.c src/dcp/*.c src/math/*.c src/*.h src/dcp/*.h src/math/*.h sysinc/*.h
|
||||||
format-check:
|
format-check:
|
||||||
$(CLANG_FORMAT) --dry-run --Werror src/*.c src/*.h sysinc/*.h
|
$(CLANG_FORMAT) --dry-run --Werror src/*.c src/*.h src/dcp/*.c src/dcp/*.h sysinc/*.h
|
||||||
rustfmt:
|
rustfmt:
|
||||||
cd rust && cargo fmt
|
cd rust && cargo fmt
|
||||||
rustfmt-check:
|
rustfmt-check:
|
||||||
|
|
273
src/dcp/parser.c
Normal file
273
src/dcp/parser.c
Normal file
|
@ -0,0 +1,273 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only OR MIT
|
||||||
|
/* Copyright 2021 Alyssa Rosenzweig <alyssa@rosenzweig.io> */
|
||||||
|
|
||||||
|
#include "malloc.h"
|
||||||
|
#include "parser.h"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
#include "../utils.h"
|
||||||
|
|
||||||
|
#define DCP_PARSE_HEADER 0xd3
|
||||||
|
|
||||||
|
enum dcp_parse_type {
|
||||||
|
DCP_TYPE_DICTIONARY = 1,
|
||||||
|
DCP_TYPE_ARRAY = 2,
|
||||||
|
DCP_TYPE_INT64 = 4,
|
||||||
|
DCP_TYPE_STRING = 9,
|
||||||
|
DCP_TYPE_BLOB = 10,
|
||||||
|
DCP_TYPE_BOOL = 11
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dcp_parse_tag {
|
||||||
|
unsigned int size : 24;
|
||||||
|
enum dcp_parse_type type : 5;
|
||||||
|
unsigned int padding : 2;
|
||||||
|
bool last : 1;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
static void *parse_bytes(struct dcp_parse_ctx *ctx, size_t count)
|
||||||
|
{
|
||||||
|
void *ptr = ctx->blob + ctx->pos;
|
||||||
|
|
||||||
|
if (ctx->pos + count > ctx->len)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ctx->pos += count;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 *parse_u32(struct dcp_parse_ctx *ctx)
|
||||||
|
{
|
||||||
|
return parse_bytes(ctx, sizeof(u32));
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct dcp_parse_tag *parse_tag(struct dcp_parse_ctx *ctx)
|
||||||
|
{
|
||||||
|
struct dcp_parse_tag *tag;
|
||||||
|
|
||||||
|
/* Align to 32-bits */
|
||||||
|
ctx->pos = ALIGN_UP(ctx->pos, 4);
|
||||||
|
|
||||||
|
tag = parse_bytes(ctx, sizeof(struct dcp_parse_tag));
|
||||||
|
|
||||||
|
if (!tag)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (tag->padding)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct dcp_parse_tag *parse_tag_of_type(struct dcp_parse_ctx *ctx, enum dcp_parse_type type)
|
||||||
|
{
|
||||||
|
struct dcp_parse_tag *tag = parse_tag(ctx);
|
||||||
|
|
||||||
|
if (!tag)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (tag->type != type)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int skip(struct dcp_parse_ctx *handle)
|
||||||
|
{
|
||||||
|
struct dcp_parse_tag *tag = parse_tag(handle);
|
||||||
|
int ret = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!tag)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
switch (tag->type) {
|
||||||
|
case DCP_TYPE_DICTIONARY:
|
||||||
|
for (i = 0; i < tag->size; ++i) {
|
||||||
|
ret |= skip(handle); /* key */
|
||||||
|
ret |= skip(handle); /* value */
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
case DCP_TYPE_ARRAY:
|
||||||
|
for (i = 0; i < tag->size; ++i)
|
||||||
|
ret |= skip(handle);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
case DCP_TYPE_INT64:
|
||||||
|
handle->pos += sizeof(s64);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case DCP_TYPE_STRING:
|
||||||
|
case DCP_TYPE_BLOB:
|
||||||
|
handle->pos += tag->size;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case DCP_TYPE_BOOL:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Caller must free the result */
|
||||||
|
static char *parse_string(struct dcp_parse_ctx *handle)
|
||||||
|
{
|
||||||
|
struct dcp_parse_tag *tag = parse_tag_of_type(handle, DCP_TYPE_STRING);
|
||||||
|
const char *in;
|
||||||
|
char *out;
|
||||||
|
|
||||||
|
if (!tag)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
in = parse_bytes(handle, tag->size);
|
||||||
|
if (!in)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
out = malloc(tag->size + 1);
|
||||||
|
|
||||||
|
memcpy(out, in, tag->size);
|
||||||
|
out[tag->size] = '\0';
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_int(struct dcp_parse_ctx *handle, s64 *value)
|
||||||
|
{
|
||||||
|
void *tag = parse_tag_of_type(handle, DCP_TYPE_INT64);
|
||||||
|
s64 *in;
|
||||||
|
|
||||||
|
if (!tag)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
in = parse_bytes(handle, sizeof(s64));
|
||||||
|
|
||||||
|
if (!in)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
memcpy(value, in, sizeof(*value));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// currently unused
|
||||||
|
#if 0
|
||||||
|
static int parse_bool(struct dcp_parse_ctx *handle, bool *b)
|
||||||
|
{
|
||||||
|
struct dcp_parse_tag *tag = parse_tag_of_type(handle, DCP_TYPE_BOOL);
|
||||||
|
|
||||||
|
if (!tag)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
*b = !!tag->size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct iterator {
|
||||||
|
struct dcp_parse_ctx *handle;
|
||||||
|
u32 idx, len;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int iterator_begin(struct dcp_parse_ctx *handle, struct iterator *it, bool dict)
|
||||||
|
{
|
||||||
|
struct dcp_parse_tag *tag;
|
||||||
|
enum dcp_parse_type type = dict ? DCP_TYPE_DICTIONARY : DCP_TYPE_ARRAY;
|
||||||
|
|
||||||
|
*it = (struct iterator){.handle = handle, .idx = 0};
|
||||||
|
|
||||||
|
tag = parse_tag_of_type(it->handle, type);
|
||||||
|
if (!tag)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
it->len = tag->size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define dcp_parse_foreach_in_array(handle, it) \
|
||||||
|
for (iterator_begin(handle, &it, false); it.idx < it.len; ++it.idx)
|
||||||
|
#define dcp_parse_foreach_in_dict(handle, it) \
|
||||||
|
for (iterator_begin(handle, &it, true); it.idx < it.len; ++it.idx)
|
||||||
|
|
||||||
|
int parse(void *blob, size_t size, struct dcp_parse_ctx *ctx)
|
||||||
|
{
|
||||||
|
u32 *header;
|
||||||
|
|
||||||
|
*ctx = (struct dcp_parse_ctx){
|
||||||
|
.blob = blob,
|
||||||
|
.len = size,
|
||||||
|
.pos = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
header = parse_u32(ctx);
|
||||||
|
if (!header)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (*header != DCP_PARSE_HEADER)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_epic_service_init(struct dcp_parse_ctx *handle, char **name, char **class, s64 *unit)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct iterator it;
|
||||||
|
bool parsed_unit = false;
|
||||||
|
bool parsed_name = false;
|
||||||
|
bool parsed_class = false;
|
||||||
|
|
||||||
|
*name = NULL;
|
||||||
|
*class = NULL;
|
||||||
|
|
||||||
|
dcp_parse_foreach_in_dict(handle, it)
|
||||||
|
{
|
||||||
|
char *key = parse_string(it.handle);
|
||||||
|
|
||||||
|
if (!key) {
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(key, "EPICName")) {
|
||||||
|
*name = parse_string(it.handle);
|
||||||
|
if (!*name)
|
||||||
|
ret = -1;
|
||||||
|
else
|
||||||
|
parsed_name = true;
|
||||||
|
} else if (!strcmp(key, "EPICProviderClass")) {
|
||||||
|
*class = parse_string(it.handle);
|
||||||
|
if (!*class)
|
||||||
|
ret = -1;
|
||||||
|
else
|
||||||
|
parsed_class = true;
|
||||||
|
} else if (!strcmp(key, "EPICUnit")) {
|
||||||
|
ret = parse_int(it.handle, unit);
|
||||||
|
if (!ret)
|
||||||
|
parsed_unit = true;
|
||||||
|
} else {
|
||||||
|
skip(it.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(key);
|
||||||
|
if (ret)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parsed_unit || !parsed_name || !parsed_class)
|
||||||
|
ret = -1;
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
if (*name) {
|
||||||
|
free(*name);
|
||||||
|
*name = NULL;
|
||||||
|
}
|
||||||
|
if (*class) {
|
||||||
|
free(*class);
|
||||||
|
*class = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
18
src/dcp/parser.h
Normal file
18
src/dcp/parser.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only OR MIT
|
||||||
|
/* Copyright 2021 Alyssa Rosenzweig <alyssa@rosenzweig.io> */
|
||||||
|
|
||||||
|
#ifndef __APPLE_DCP_PARSER_H__
|
||||||
|
#define __APPLE_DCP_PARSER_H__
|
||||||
|
|
||||||
|
#include "../types.h"
|
||||||
|
|
||||||
|
struct dcp_parse_ctx {
|
||||||
|
void *blob;
|
||||||
|
u32 pos, len;
|
||||||
|
};
|
||||||
|
|
||||||
|
int parse(void *blob, size_t size, struct dcp_parse_ctx *ctx);
|
||||||
|
|
||||||
|
int parse_epic_service_init(struct dcp_parse_ctx *handle, char **name, char **class, s64 *unit);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue