Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bf0eb898 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nv50-/disp: audit and version DAC_PWR method



The full object interfaces are about to be exposed to userspace, so we
need to check for any security-related issues and version the structs
to make it easier to handle any changes we may need in the future.

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 2c04ae01
Loading
Loading
Loading
Loading
+24 −10
Original line number Diff line number Diff line
@@ -22,8 +22,10 @@
 * Authors: Ben Skeggs
 */

#include <core/os.h>
#include <core/client.h>
#include <core/class.h>
#include <nvif/unpack.h>
#include <nvif/class.h>

#include <subdev/bios.h>
#include <subdev/bios/dcb.h>
@@ -32,13 +34,28 @@
#include "nv50.h"

int
nv50_dac_power(struct nv50_disp_priv *priv, int or, u32 data)
nv50_dac_power(NV50_DISP_MTHD_V1)
{
	const u32 stat = (data & NV50_DISP_DAC_PWR_HSYNC) |
		         (data & NV50_DISP_DAC_PWR_VSYNC) |
		         (data & NV50_DISP_DAC_PWR_DATA) |
		         (data & NV50_DISP_DAC_PWR_STATE);
	const u32 doff = (or * 0x800);
	const u32 doff = outp->or * 0x800;
	union {
		struct nv50_disp_dac_pwr_v0 v0;
	} *args = data;
	u32 stat;
	int ret;

	nv_ioctl(object, "disp dac pwr size %d\n", size);
	if (nvif_unpack(args->v0, 0, 0, false)) {
		nv_ioctl(object, "disp dac pwr vers %d state %d data %d "
				 "vsync %d hsync %d\n",
			 args->v0.version, args->v0.state, args->v0.data,
			 args->v0.vsync, args->v0.hsync);
		stat  = 0x00000040 * !args->v0.state;
		stat |= 0x00000010 * !args->v0.data;
		stat |= 0x00000004 * !args->v0.vsync;
		stat |= 0x00000001 * !args->v0.hsync;
	} else
		return ret;

	nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
	nv_mask(priv, 0x61a004 + doff, 0xc000007f, 0x80000000 | stat);
	nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
@@ -80,9 +97,6 @@ nv50_dac_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
		return -EINVAL;

	switch (mthd & ~0x3f) {
	case NV50_DISP_DAC_PWR:
		ret = priv->dac.power(priv, or, data[0]);
		break;
	case NV50_DISP_DAC_LOAD:
		ret = priv->dac.sense(priv, or, data[0]);
		if (ret >= 0) {
+71 −2
Original line number Diff line number Diff line
@@ -23,10 +23,13 @@
 */

#include <core/object.h>
#include <core/client.h>
#include <core/parent.h>
#include <core/handle.h>
#include <core/class.h>
#include <core/enum.h>
#include <core/class.h>
#include <nvif/unpack.h>
#include <nvif/class.h>

#include <subdev/bios.h>
#include <subdev/bios/dcb.h>
@@ -839,6 +842,72 @@ nv50_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd,
	return 0;
}

int
nv50_disp_base_mthd(struct nouveau_object *object, u32 mthd,
		    void *data, u32 size)
{
	union {
		struct nv50_disp_mthd_v0 v0;
		struct nv50_disp_mthd_v1 v1;
	} *args = data;
	struct nv50_disp_priv *priv = (void *)object->engine;
	struct nvkm_output *outp = NULL;
	struct nvkm_output *temp;
	u16 type, mask = 0;
	int head, ret;

	if (mthd != NV50_DISP_MTHD)
		return -EINVAL;

	nv_ioctl(object, "disp mthd size %d\n", size);
	if (nvif_unpack(args->v0, 0, 0, true)) {
		nv_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
			 args->v0.version, args->v0.method, args->v0.head);
		mthd = args->v0.method;
		head = args->v0.head;
	} else
	if (nvif_unpack(args->v1, 1, 1, true)) {
		nv_ioctl(object, "disp mthd vers %d mthd %02x "
				 "type %04x mask %04x\n",
			 args->v1.version, args->v1.method,
			 args->v1.hasht, args->v1.hashm);
		mthd = args->v1.method;
		type = args->v1.hasht;
		mask = args->v1.hashm;
		head = ffs((mask >> 8) & 0x0f) - 1;
	} else
		return ret;

	if (head < 0 || head >= priv->head.nr)
		return -ENXIO;

	if (mask) {
		list_for_each_entry(temp, &priv->base.outp, head) {
			if ((temp->info.hasht         == type) &&
			    (temp->info.hashm & mask) == mask) {
				outp = temp;
				break;
			}
		}
		if (outp == NULL)
			return -ENXIO;
	}

	switch (mthd) {
	default:
		break;
	}

	switch (mthd * !!outp) {
	case NV50_DISP_MTHD_V1_DAC_PWR:
		return priv->dac.power(object, priv, data, size, head, outp);
	default:
		break;
	}

	return -EINVAL;
}

int
nv50_disp_base_ctor(struct nouveau_object *parent,
		    struct nouveau_object *engine,
@@ -954,6 +1023,7 @@ nv50_disp_base_ofuncs = {
	.dtor = nv50_disp_base_dtor,
	.init = nv50_disp_base_init,
	.fini = nv50_disp_base_fini,
	.mthd = nv50_disp_base_mthd,
};

static struct nouveau_omthds
@@ -961,7 +1031,6 @@ nv50_disp_base_omthds[] = {
	{ HEAD_MTHD(NV50_DISP_SCANOUTPOS)     , nv50_disp_base_scanoutpos },
	{ SOR_MTHD(NV50_DISP_SOR_PWR)         , nv50_sor_mthd },
	{ SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
	{ DAC_MTHD(NV50_DISP_DAC_PWR)         , nv50_dac_mthd },
	{ DAC_MTHD(NV50_DISP_DAC_LOAD)        , nv50_dac_mthd },
	{ PIOR_MTHD(NV50_DISP_PIOR_PWR)       , nv50_pior_mthd },
	{ PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR)  , nv50_pior_mthd },
+8 −2
Original line number Diff line number Diff line
@@ -24,6 +24,11 @@ struct nv50_disp_impl {
	} mthd;
};

#define NV50_DISP_MTHD_ struct nouveau_object *object,                         \
	struct nv50_disp_priv *priv, void *data, u32 size
#define NV50_DISP_MTHD_V0 NV50_DISP_MTHD_, int head
#define NV50_DISP_MTHD_V1 NV50_DISP_MTHD_, int head, struct nvkm_output *outp

struct nv50_disp_priv {
	struct nouveau_disp base;
	struct nouveau_oclass *sclass;
@@ -36,7 +41,7 @@ struct nv50_disp_priv {
	} head;
	struct {
		int nr;
		int (*power)(struct nv50_disp_priv *, int dac, u32 data);
		int (*power)(NV50_DISP_MTHD_V1);
		int (*sense)(struct nv50_disp_priv *, int dac, u32 load);
	} dac;
	struct {
@@ -56,11 +61,12 @@ struct nv50_disp_priv {
#define HEAD_MTHD(n) (n), (n) + 0x03

int nv50_disp_base_scanoutpos(struct nouveau_object *, u32, void *, u32);
int nv50_disp_base_mthd(struct nouveau_object *, u32, void *, u32);

#define DAC_MTHD(n) (n), (n) + 0x03

int nv50_dac_mthd(struct nouveau_object *, u32, void *, u32);
int nv50_dac_power(struct nv50_disp_priv *, int, u32);
int nv50_dac_power(NV50_DISP_MTHD_V1);
int nv50_dac_sense(struct nv50_disp_priv *, int, u32);

#define SOR_MTHD(n) (n), (n) + 0x3f
+0 −1
Original line number Diff line number Diff line
@@ -218,7 +218,6 @@ nv84_disp_base_omthds[] = {
	{ SOR_MTHD(NV50_DISP_SOR_PWR)         , nv50_sor_mthd },
	{ SOR_MTHD(NV84_DISP_SOR_HDMI_PWR)    , nv50_sor_mthd },
	{ SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
	{ DAC_MTHD(NV50_DISP_DAC_PWR)         , nv50_dac_mthd },
	{ DAC_MTHD(NV50_DISP_DAC_LOAD)        , nv50_dac_mthd },
	{ PIOR_MTHD(NV50_DISP_PIOR_PWR)       , nv50_pior_mthd },
	{ PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR)  , nv50_pior_mthd },
+0 −1
Original line number Diff line number Diff line
@@ -78,7 +78,6 @@ nv94_disp_base_omthds[] = {
	{ SOR_MTHD(NV84_DISP_SOR_HDMI_PWR)    , nv50_sor_mthd },
	{ SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
	{ SOR_MTHD(NV94_DISP_SOR_DP_PWR)      , nv50_sor_mthd },
	{ DAC_MTHD(NV50_DISP_DAC_PWR)         , nv50_dac_mthd },
	{ DAC_MTHD(NV50_DISP_DAC_LOAD)        , nv50_dac_mthd },
	{ PIOR_MTHD(NV50_DISP_PIOR_PWR)       , nv50_pior_mthd },
	{ PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR)  , nv50_pior_mthd },
Loading