1e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project/*
2e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
3e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project *
4e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * you may not use this file except in compliance with the License.
6e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * You may obtain a copy of the License at
7e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project *
8e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project *
10e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * See the License for the specific language governing permissions and
14e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * limitations under the License.
15e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project */
16e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
17e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <dirent.h>
18e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <errno.h>
19e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <fcntl.h>
20e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <stdint.h>
21e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <stdlib.h>
22e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <sys/stat.h>
23e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <sys/types.h>
24e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <unistd.h>
25e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
26e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <pagemap/pagemap.h>
27e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
28e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectint pm_kernel_create(pm_kernel_t **ker_out) {
29e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    pm_kernel_t *ker;
30e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    int error;
31e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
32e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (!ker_out)
33e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        return 1;
34e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
35e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    ker = calloc(1, sizeof(*ker));
36e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (!ker)
37e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        return errno;
38e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
39e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    ker->kpagecount_fd = open("/proc/kpagecount", O_RDONLY);
40e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (ker->kpagecount_fd < 0) {
41e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        error = errno;
42e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        free(ker);
43e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        return error;
44e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    }
45e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
46e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    ker->kpageflags_fd = open("/proc/kpageflags", O_RDONLY);
47e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (ker->kpageflags_fd < 0) {
48e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        error = errno;
49e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        close(ker->kpagecount_fd);
50e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        free(ker);
51e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        return error;
52e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    }
53e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
54e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    ker->pagesize = getpagesize();
55e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
56e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    *ker_out = ker;
57e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
58e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    return 0;
59e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project}
60e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
61e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#define INIT_PIDS 20
62e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectint pm_kernel_pids(pm_kernel_t *ker, pid_t **pids_out, size_t *len) {
63e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    DIR *proc;
64e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    struct dirent *dir;
65e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    pid_t pid, *pids, *new_pids;
66e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    size_t pids_count, pids_size;
67e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    int error;
68e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
69e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    proc = opendir("/proc");
70e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (!proc)
71e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        return errno;
72e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
73e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    pids = malloc(INIT_PIDS * sizeof(pid_t));
74e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (!pids) {
75e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        closedir(proc);
76e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        return errno;
77e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    }
78e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    pids_count = 0; pids_size = INIT_PIDS;
79e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
80e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    while ((dir = readdir(proc))) {
81e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        if (sscanf(dir->d_name, "%d", &pid) < 1)
82e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            continue;
83e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
84e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        if (pids_count >= pids_size) {
85e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            new_pids = realloc(pids, 2 * pids_size * sizeof(pid_t));
86e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            if (!new_pids) {
87e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project                error = errno;
88e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project                free(pids);
89e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project                closedir(proc);
90e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project                return error;
91e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            }
92e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            pids = new_pids;
93e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            pids_size = 2 * pids_size;
94e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        }
95e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
96e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        pids[pids_count] = pid;
97e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
98e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        pids_count++;
99e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    }
100e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
101e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    closedir(proc);
102e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
103e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    new_pids = realloc(pids, pids_count * sizeof(pid_t));
104e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (!new_pids) {
105e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        error = errno;
106e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        free(pids);
107e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        return error;
108e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    }
109e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
110e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    *pids_out = new_pids;
111e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    *len = pids_count;
112e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
113e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    return 0;
114e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project}
115e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
116e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectint pm_kernel_count(pm_kernel_t *ker, unsigned long pfn, uint64_t *count_out) {
117e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    off_t off;
118e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
119e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (!ker || !count_out)
120e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        return -1;
121e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
122e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    off = lseek(ker->kpagecount_fd, pfn * sizeof(uint64_t), SEEK_SET);
123e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (off == (off_t)-1)
124e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        return errno;
125e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (read(ker->kpagecount_fd, count_out, sizeof(uint64_t)) <
126e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        (ssize_t)sizeof(uint64_t))
127e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        return errno;
128e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
129e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    return 0;
130e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project}
131e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
132e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectint pm_kernel_flags(pm_kernel_t *ker, unsigned long pfn, uint64_t *flags_out) {
133e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    off_t off;
134e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
135e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (!ker || !flags_out)
136e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        return -1;
137e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
138e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    off = lseek(ker->kpageflags_fd, pfn * sizeof(uint64_t), SEEK_SET);
139e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (off == (off_t)-1)
140e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        return errno;
141e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (read(ker->kpageflags_fd, flags_out, sizeof(uint64_t)) <
142e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        (ssize_t)sizeof(uint64_t))
143e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        return errno;
144e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
145e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    return 0;
146e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project}
147e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
148e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectint pm_kernel_destroy(pm_kernel_t *ker) {
149e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (!ker)
150e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        return -1;
151e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
152e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    close(ker->kpagecount_fd);
153e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    close(ker->kpageflags_fd);
154e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
155e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    free(ker);
156e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
157e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    return 0;
158e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project}
159