Commit 2313022e authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'uml-for-linus-6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/uml/linux

Pull UML updates from Richard Weinberger:

 - Fixes for -Wmissing-prototypes warnings and further cleanup

 - Remove callback returning void from rtc and virtio drivers

 - Fix bash location

* tag 'uml-for-linus-6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/uml/linux: (26 commits)
  um: virtio_uml: Convert to platform remove callback returning void
  um: rtc: Convert to platform remove callback returning void
  um: Remove unused do_get_thread_area function
  um: Fix -Wmissing-prototypes warnings for __vdso_*
  um: Add an internal header shared among the user code
  um: Fix the declaration of kasan_map_memory
  um: Fix the -Wmissing-prototypes warning for get_thread_reg
  um: Fix the -Wmissing-prototypes warning for __switch_mm
  um: Fix -Wmissing-prototypes warnings for (rt_)sigreturn
  um: Stop tracking host PID in cpu_tasks
  um: process: remove unused 'n' variable
  um: vector: remove unused len variable/calculation
  um: vector: fix bpfflash parameter evaluation
  um: slirp: remove set but unused variable 'pid'
  um: signal: move pid variable where needed
  um: Makefile: use bash from the environment
  um: Add winch to winch_handlers before registering winch IRQ
  um: Fix -Wmissing-prototypes warnings for __warp_* and foo
  um: Fix -Wmissing-prototypes warnings for text_poke*
  um: Move declarations to proper headers
  ...
parents 56fb6f92 919e3ece
...@@ -20,7 +20,7 @@ endif ...@@ -20,7 +20,7 @@ endif
ARCH_DIR := arch/um ARCH_DIR := arch/um
# We require bash because the vmlinux link and loader script cpp use bash # We require bash because the vmlinux link and loader script cpp use bash
# features. # features.
SHELL := /bin/bash SHELL := bash
MODE_INCLUDE += -I$(srctree)/$(ARCH_DIR)/include/shared/skas MODE_INCLUDE += -I$(srctree)/$(ARCH_DIR)/include/shared/skas
......
...@@ -676,23 +676,25 @@ void register_winch_irq(int fd, int tty_fd, int pid, struct tty_port *port, ...@@ -676,23 +676,25 @@ void register_winch_irq(int fd, int tty_fd, int pid, struct tty_port *port,
goto cleanup; goto cleanup;
} }
*winch = ((struct winch) { .list = LIST_HEAD_INIT(winch->list), *winch = ((struct winch) { .fd = fd,
.fd = fd,
.tty_fd = tty_fd, .tty_fd = tty_fd,
.pid = pid, .pid = pid,
.port = port, .port = port,
.stack = stack }); .stack = stack });
spin_lock(&winch_handler_lock);
list_add(&winch->list, &winch_handlers);
spin_unlock(&winch_handler_lock);
if (um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, if (um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt,
IRQF_SHARED, "winch", winch) < 0) { IRQF_SHARED, "winch", winch) < 0) {
printk(KERN_ERR "register_winch_irq - failed to register " printk(KERN_ERR "register_winch_irq - failed to register "
"IRQ\n"); "IRQ\n");
goto out_free;
}
spin_lock(&winch_handler_lock); spin_lock(&winch_handler_lock);
list_add(&winch->list, &winch_handlers); list_del(&winch->list);
spin_unlock(&winch_handler_lock); spin_unlock(&winch_handler_lock);
goto out_free;
}
return; return;
......
...@@ -15,7 +15,7 @@ struct pcap_init { ...@@ -15,7 +15,7 @@ struct pcap_init {
char *filter; char *filter;
}; };
void pcap_init_kern(struct net_device *dev, void *data) static void pcap_init_kern(struct net_device *dev, void *data)
{ {
struct uml_net_private *pri; struct uml_net_private *pri;
struct pcap_data *ppri; struct pcap_data *ppri;
...@@ -50,7 +50,7 @@ static const struct net_kern_info pcap_kern_info = { ...@@ -50,7 +50,7 @@ static const struct net_kern_info pcap_kern_info = {
.write = pcap_write, .write = pcap_write,
}; };
int pcap_setup(char *str, char **mac_out, void *data) static int pcap_setup(char *str, char **mac_out, void *data)
{ {
struct pcap_init *init = data; struct pcap_init *init = data;
char *remain, *host_if = NULL, *options[2] = { NULL, NULL }; char *remain, *host_if = NULL, *options[2] = { NULL, NULL };
......
...@@ -168,16 +168,15 @@ static int uml_rtc_probe(struct platform_device *pdev) ...@@ -168,16 +168,15 @@ static int uml_rtc_probe(struct platform_device *pdev)
return err; return err;
} }
static int uml_rtc_remove(struct platform_device *pdev) static void uml_rtc_remove(struct platform_device *pdev)
{ {
device_init_wakeup(&pdev->dev, 0); device_init_wakeup(&pdev->dev, 0);
uml_rtc_cleanup(); uml_rtc_cleanup();
return 0;
} }
static struct platform_driver uml_rtc_driver = { static struct platform_driver uml_rtc_driver = {
.probe = uml_rtc_probe, .probe = uml_rtc_probe,
.remove = uml_rtc_remove, .remove_new = uml_rtc_remove,
.driver = { .driver = {
.name = "uml-rtc", .name = "uml-rtc",
}, },
......
...@@ -49,7 +49,7 @@ static int slirp_tramp(char **argv, int fd) ...@@ -49,7 +49,7 @@ static int slirp_tramp(char **argv, int fd)
static int slirp_open(void *data) static int slirp_open(void *data)
{ {
struct slirp_data *pri = data; struct slirp_data *pri = data;
int fds[2], pid, err; int fds[2], err;
err = os_pipe(fds, 1, 1); err = os_pipe(fds, 1, 1);
if (err) if (err)
...@@ -60,7 +60,6 @@ static int slirp_open(void *data) ...@@ -60,7 +60,6 @@ static int slirp_open(void *data)
printk(UM_KERN_ERR "slirp_tramp failed - errno = %d\n", -err); printk(UM_KERN_ERR "slirp_tramp failed - errno = %d\n", -err);
goto out; goto out;
} }
pid = err;
pri->slave = fds[1]; pri->slave = fds[1];
pri->slip.pos = 0; pri->slip.pos = 0;
......
...@@ -1092,7 +1092,7 @@ static int __init ubd_init(void) ...@@ -1092,7 +1092,7 @@ static int __init ubd_init(void)
if (irq_req_buffer == NULL) { if (irq_req_buffer == NULL) {
printk(KERN_ERR "Failed to initialize ubd buffering\n"); printk(KERN_ERR "Failed to initialize ubd buffering\n");
return -1; return -ENOMEM;
} }
io_req_buffer = kmalloc_array(UBD_REQ_BUFFER_SIZE, io_req_buffer = kmalloc_array(UBD_REQ_BUFFER_SIZE,
sizeof(struct io_thread_req *), sizeof(struct io_thread_req *),
...@@ -1103,7 +1103,7 @@ static int __init ubd_init(void) ...@@ -1103,7 +1103,7 @@ static int __init ubd_init(void)
if (io_req_buffer == NULL) { if (io_req_buffer == NULL) {
printk(KERN_ERR "Failed to initialize ubd buffering\n"); printk(KERN_ERR "Failed to initialize ubd buffering\n");
return -1; return -ENOMEM;
} }
platform_driver_register(&ubd_driver); platform_driver_register(&ubd_driver);
mutex_lock(&ubd_lock); mutex_lock(&ubd_lock);
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include <os.h> #include <os.h>
#include <poll.h> #include <poll.h>
struct pollfd kernel_pollfd; static struct pollfd kernel_pollfd;
int start_io_thread(unsigned long sp, int *fd_out) int start_io_thread(unsigned long sp, int *fd_out)
{ {
......
...@@ -141,7 +141,7 @@ static bool get_bpf_flash(struct arglist *def) ...@@ -141,7 +141,7 @@ static bool get_bpf_flash(struct arglist *def)
if (allow != NULL) { if (allow != NULL) {
if (kstrtoul(allow, 10, &result) == 0) if (kstrtoul(allow, 10, &result) == 0)
return (allow > 0); return result > 0;
} }
return false; return false;
} }
...@@ -712,11 +712,9 @@ static struct vector_device *find_device(int n) ...@@ -712,11 +712,9 @@ static struct vector_device *find_device(int n)
static int vector_parse(char *str, int *index_out, char **str_out, static int vector_parse(char *str, int *index_out, char **str_out,
char **error_out) char **error_out)
{ {
int n, len, err; int n, err;
char *start = str; char *start = str;
len = strlen(str);
while ((*str != ':') && (strlen(str) > 1)) while ((*str != ':') && (strlen(str) > 1))
str++; str++;
if (*str != ':') { if (*str != ':') {
......
...@@ -1241,12 +1241,11 @@ static int virtio_uml_probe(struct platform_device *pdev) ...@@ -1241,12 +1241,11 @@ static int virtio_uml_probe(struct platform_device *pdev)
return rc; return rc;
} }
static int virtio_uml_remove(struct platform_device *pdev) static void virtio_uml_remove(struct platform_device *pdev)
{ {
struct virtio_uml_device *vu_dev = platform_get_drvdata(pdev); struct virtio_uml_device *vu_dev = platform_get_drvdata(pdev);
unregister_virtio_device(&vu_dev->vdev); unregister_virtio_device(&vu_dev->vdev);
return 0;
} }
/* Command line device list */ /* Command line device list */
...@@ -1445,7 +1444,7 @@ static int virtio_uml_resume(struct platform_device *pdev) ...@@ -1445,7 +1444,7 @@ static int virtio_uml_resume(struct platform_device *pdev)
static struct platform_driver virtio_uml_driver = { static struct platform_driver virtio_uml_driver = {
.probe = virtio_uml_probe, .probe = virtio_uml_probe,
.remove = virtio_uml_remove, .remove_new = virtio_uml_remove,
.driver = { .driver = {
.name = "virtio-uml", .name = "virtio-uml",
.of_match_table = virtio_uml_match, .of_match_table = virtio_uml_match,
......
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
#ifdef CONFIG_KASAN #ifdef CONFIG_KASAN
void kasan_init(void); void kasan_init(void);
void kasan_map_memory(void *start, unsigned long len);
extern int kasan_um_is_ready; extern int kasan_um_is_ready;
#ifdef CONFIG_STATIC_LINK #ifdef CONFIG_STATIC_LINK
......
...@@ -14,8 +14,6 @@ typedef struct mm_context { ...@@ -14,8 +14,6 @@ typedef struct mm_context {
struct uml_arch_mm_context arch; struct uml_arch_mm_context arch;
} mm_context_t; } mm_context_t;
extern void __switch_mm(struct mm_id * mm_idp);
/* Avoid tangled inclusion with asm/ldt.h */ /* Avoid tangled inclusion with asm/ldt.h */
extern long init_new_ldt(struct mm_context *to_mm, struct mm_context *from_mm); extern long init_new_ldt(struct mm_context *to_mm, struct mm_context *from_mm);
extern void free_ldt(struct mm_context *mm); extern void free_ldt(struct mm_context *mm);
......
...@@ -94,7 +94,6 @@ extern struct cpuinfo_um boot_cpu_data; ...@@ -94,7 +94,6 @@ extern struct cpuinfo_um boot_cpu_data;
#define current_cpu_data boot_cpu_data #define current_cpu_data boot_cpu_data
#define cache_line_size() (boot_cpu_data.cache_alignment) #define cache_line_size() (boot_cpu_data.cache_alignment)
extern unsigned long get_thread_reg(int reg, jmp_buf *buf);
#define KSTK_REG(tsk, reg) get_thread_reg(reg, &tsk->thread.switch_buf) #define KSTK_REG(tsk, reg) get_thread_reg(reg, &tsk->thread.switch_buf)
extern unsigned long __get_wchan(struct task_struct *p); extern unsigned long __get_wchan(struct task_struct *p);
......
...@@ -36,6 +36,9 @@ extern long subarch_ptrace(struct task_struct *child, long request, ...@@ -36,6 +36,9 @@ extern long subarch_ptrace(struct task_struct *child, long request,
extern unsigned long getreg(struct task_struct *child, int regno); extern unsigned long getreg(struct task_struct *child, int regno);
extern int putreg(struct task_struct *child, int regno, unsigned long value); extern int putreg(struct task_struct *child, int regno, unsigned long value);
extern int poke_user(struct task_struct *child, long addr, long data);
extern int peek_user(struct task_struct *child, long addr, long data);
extern int arch_set_tls(struct task_struct *new, unsigned long tls); extern int arch_set_tls(struct task_struct *new, unsigned long tls);
extern void clear_flushed_tls(struct task_struct *task); extern void clear_flushed_tls(struct task_struct *task);
extern int syscall_trace_enter(struct pt_regs *regs); extern int syscall_trace_enter(struct pt_regs *regs);
......
...@@ -31,7 +31,6 @@ ...@@ -31,7 +31,6 @@
#include <sysdep/ptrace.h> #include <sysdep/ptrace.h>
struct cpu_task { struct cpu_task {
int pid;
void *task; void *task;
}; };
......
...@@ -41,6 +41,7 @@ extern void uml_pm_wake(void); ...@@ -41,6 +41,7 @@ extern void uml_pm_wake(void);
extern int start_uml(void); extern int start_uml(void);
extern void paging_init(void); extern void paging_init(void);
extern int parse_iomem(char *str, int *add);
extern void uml_cleanup(void); extern void uml_cleanup(void);
extern void do_uml_exitcalls(void); extern void do_uml_exitcalls(void);
...@@ -66,4 +67,6 @@ extern void fatal_sigsegv(void) __attribute__ ((noreturn)); ...@@ -66,4 +67,6 @@ extern void fatal_sigsegv(void) __attribute__ ((noreturn));
void um_idle_sleep(void); void um_idle_sleep(void);
void kasan_map_memory(void *start, size_t len);
#endif #endif
...@@ -15,4 +15,6 @@ struct mm_id { ...@@ -15,4 +15,6 @@ struct mm_id {
int kill; int kill;
}; };
void __switch_mm(struct mm_id *mm_idp);
#endif #endif
...@@ -13,7 +13,7 @@ extern void kfree(const void *ptr); ...@@ -13,7 +13,7 @@ extern void kfree(const void *ptr);
extern void *vmalloc_noprof(unsigned long size); extern void *vmalloc_noprof(unsigned long size);
#define vmalloc(...) vmalloc_noprof(__VA_ARGS__) #define vmalloc(...) vmalloc_noprof(__VA_ARGS__)
extern void vfree(void *ptr); extern void vfree(const void *ptr);
#endif /* __UM_MALLOC_H__ */ #endif /* __UM_MALLOC_H__ */
......
...@@ -57,7 +57,7 @@ static struct kmsg_dumper kmsg_dumper = { ...@@ -57,7 +57,7 @@ static struct kmsg_dumper kmsg_dumper = {
.dump = kmsg_dumper_stdout .dump = kmsg_dumper_stdout
}; };
int __init kmsg_dumper_stdout_init(void) static int __init kmsg_dumper_stdout_init(void)
{ {
return kmsg_dump_register(&kmsg_dumper); return kmsg_dump_register(&kmsg_dumper);
} }
......
...@@ -12,12 +12,14 @@ ...@@ -12,12 +12,14 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <asm/fixmap.h> #include <asm/fixmap.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/pgalloc.h>
#include <as-layout.h> #include <as-layout.h>
#include <init.h> #include <init.h>
#include <kern.h> #include <kern.h>
#include <kern_util.h> #include <kern_util.h>
#include <mem_user.h> #include <mem_user.h>
#include <os.h> #include <os.h>
#include <um_malloc.h>
#include <linux/sched/task.h> #include <linux/sched/task.h>
#ifdef CONFIG_KASAN #ifdef CONFIG_KASAN
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <as-layout.h> #include <as-layout.h>
#include <init.h> #include <init.h>
#include <kern.h> #include <kern.h>
#include <kern_util.h>
#include <mem_user.h> #include <mem_user.h>
#include <os.h> #include <os.h>
...@@ -161,8 +162,6 @@ __uml_setup("mem=", uml_mem_setup, ...@@ -161,8 +162,6 @@ __uml_setup("mem=", uml_mem_setup,
" Example: mem=64M\n\n" " Example: mem=64M\n\n"
); );
extern int __init parse_iomem(char *str, int *add);
__uml_setup("iomem=", parse_iomem, __uml_setup("iomem=", parse_iomem,
"iomem=<name>,<file>\n" "iomem=<name>,<file>\n"
" Configure <file> as an IO memory region named <name>.\n\n" " Configure <file> as an IO memory region named <name>.\n\n"
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/ptrace.h> #include <linux/ptrace.h>
#include <linux/random.h> #include <linux/random.h>
#include <linux/cpu.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/sched/debug.h> #include <linux/sched/debug.h>
...@@ -26,6 +27,8 @@ ...@@ -26,6 +27,8 @@
#include <linux/resume_user_mode.h> #include <linux/resume_user_mode.h>
#include <asm/current.h> #include <asm/current.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
#include <asm/switch_to.h>
#include <asm/exec.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <as-layout.h> #include <as-layout.h>
#include <kern_util.h> #include <kern_util.h>
...@@ -40,24 +43,7 @@ ...@@ -40,24 +43,7 @@
* cares about its entry, so it's OK if another processor is modifying its * cares about its entry, so it's OK if another processor is modifying its
* entry. * entry.
*/ */
struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } }; struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { NULL } };
static inline int external_pid(void)
{
/* FIXME: Need to look up userspace_pid by cpu */
return userspace_pid[0];
}
int pid_to_processor_id(int pid)
{
int i;
for (i = 0; i < ncpus; i++) {
if (cpu_tasks[i].pid == pid)
return i;
}
return -1;
}
void free_stack(unsigned long stack, int order) void free_stack(unsigned long stack, int order)
{ {
...@@ -78,13 +64,10 @@ unsigned long alloc_stack(int order, int atomic) ...@@ -78,13 +64,10 @@ unsigned long alloc_stack(int order, int atomic)
static inline void set_current(struct task_struct *task) static inline void set_current(struct task_struct *task)
{ {
cpu_tasks[task_thread_info(task)->cpu] = ((struct cpu_task) cpu_tasks[task_thread_info(task)->cpu] = ((struct cpu_task) { task });
{ external_pid(), task });
} }
extern void arch_switch_to(struct task_struct *to); struct task_struct *__switch_to(struct task_struct *from, struct task_struct *to)
void *__switch_to(struct task_struct *from, struct task_struct *to)
{ {
to->thread.prev_sched = from; to->thread.prev_sched = from;
set_current(to); set_current(to);
...@@ -119,7 +102,7 @@ int get_current_pid(void) ...@@ -119,7 +102,7 @@ int get_current_pid(void)
*/ */
void new_thread_handler(void) void new_thread_handler(void)
{ {
int (*fn)(void *), n; int (*fn)(void *);
void *arg; void *arg;
if (current->thread.prev_sched != NULL) if (current->thread.prev_sched != NULL)
...@@ -132,12 +115,12 @@ void new_thread_handler(void) ...@@ -132,12 +115,12 @@ void new_thread_handler(void)
/* /*
* callback returns only if the kernel thread execs a process * callback returns only if the kernel thread execs a process
*/ */
n = fn(arg); fn(arg);
userspace(&current->thread.regs.regs, current_thread_info()->aux_fp_regs); userspace(&current->thread.regs.regs, current_thread_info()->aux_fp_regs);
} }
/* Called magically, see new_thread_handler above */ /* Called magically, see new_thread_handler above */
void fork_handler(void) static void fork_handler(void)
{ {
force_flush_all(); force_flush_all();
...@@ -216,7 +199,6 @@ void um_idle_sleep(void) ...@@ -216,7 +199,6 @@ void um_idle_sleep(void)
void arch_cpu_idle(void) void arch_cpu_idle(void)
{ {
cpu_tasks[current_thread_info()->cpu].pid = os_getpid();
um_idle_sleep(); um_idle_sleep();
} }
...@@ -250,32 +232,22 @@ char *uml_strdup(const char *string) ...@@ -250,32 +232,22 @@ char *uml_strdup(const char *string)
} }
EXPORT_SYMBOL(uml_strdup); EXPORT_SYMBOL(uml_strdup);
int copy_to_user_proc(void __user *to, void *from, int size)
{
return copy_to_user(to, from, size);
}
int copy_from_user_proc(void *to, void __user *from, int size) int copy_from_user_proc(void *to, void __user *from, int size)
{ {
return copy_from_user(to, from, size); return copy_from_user(to, from, size);
} }
int clear_user_proc(void __user *buf, int size)
{
return clear_user(buf, size);
}
static atomic_t using_sysemu = ATOMIC_INIT(0); static atomic_t using_sysemu = ATOMIC_INIT(0);
int sysemu_supported; int sysemu_supported;
void set_using_sysemu(int value) static void set_using_sysemu(int value)
{ {
if (value > sysemu_supported) if (value > sysemu_supported)
return; return;
atomic_set(&using_sysemu, value); atomic_set(&using_sysemu, value);
} }
int get_using_sysemu(void) static int get_using_sysemu(void)
{ {
return atomic_read(&using_sysemu); return atomic_read(&using_sysemu);
} }
...@@ -313,7 +285,7 @@ static const struct proc_ops sysemu_proc_ops = { ...@@ -313,7 +285,7 @@ static const struct proc_ops sysemu_proc_ops = {
.proc_write = sysemu_proc_write, .proc_write = sysemu_proc_write,
}; };
int __init make_proc_sysemu(void) static int __init make_proc_sysemu(void)
{ {
struct proc_dir_entry *ent; struct proc_dir_entry *ent;
if (!sysemu_supported) if (!sysemu_supported)
......
...@@ -35,9 +35,6 @@ void ptrace_disable(struct task_struct *child) ...@@ -35,9 +35,6 @@ void ptrace_disable(struct task_struct *child)
user_disable_single_step(child); user_disable_single_step(child);
} }
extern int peek_user(struct task_struct * child, long addr, long data);
extern int poke_user(struct task_struct * child, long addr, long data);
long arch_ptrace(struct task_struct *child, long request, long arch_ptrace(struct task_struct *child, long request,
unsigned long addr, unsigned long data) unsigned long addr, unsigned long data)
{ {
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/oom.h> #include <linux/oom.h>
#include <linux/reboot.h>
#include <kern_util.h> #include <kern_util.h>
#include <os.h> #include <os.h>
#include <skas.h> #include <skas.h>
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/mmu_context.h>
#include <as-layout.h> #include <as-layout.h>
#include <os.h> #include <os.h>
#include <skas.h> #include <skas.h>
......
...@@ -12,17 +12,14 @@ ...@@ -12,17 +12,14 @@
#include <kern.h> #include <kern.h>
#include <os.h> #include <os.h>
#include <skas.h> #include <skas.h>
#include <kern_util.h>
extern void start_kernel(void); extern void start_kernel(void);
static int __init start_kernel_proc(void *unused) static int __init start_kernel_proc(void *unused)
{ {
int pid;
block_signals_trace(); block_signals_trace();
pid = os_getpid();
cpu_tasks[0].pid = pid;
cpu_tasks[0].task = current; cpu_tasks[0].task = current;
start_kernel(); start_kernel();
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <asm/param.h> #include <asm/param.h>
#include <kern_util.h> #include <kern_util.h>
#include <os.h> #include <os.h>
#include <linux/delay.h>
#include <linux/time-internal.h> #include <linux/time-internal.h>
#include <linux/um_timetravel.h> #include <linux/um_timetravel.h>
#include <shared/init.h> #include <shared/init.h>
...@@ -319,7 +320,7 @@ void time_travel_add_event_rel(struct time_travel_event *e, ...@@ -319,7 +320,7 @@ void time_travel_add_event_rel(struct time_travel_event *e,
time_travel_add_event(e, time_travel_time + delay_ns); time_travel_add_event(e, time_travel_time + delay_ns);
} }
void time_travel_periodic_timer(struct time_travel_event *e) static void time_travel_periodic_timer(struct time_travel_event *e)
{ {
time_travel_add_event(&time_travel_timer_event, time_travel_add_event(&time_travel_timer_event,
time_travel_time + time_travel_timer_interval); time_travel_time + time_travel_timer_interval);
...@@ -812,7 +813,7 @@ unsigned long calibrate_delay_is_known(void) ...@@ -812,7 +813,7 @@ unsigned long calibrate_delay_is_known(void)
return 0; return 0;
} }
int setup_time_travel(char *str) static int setup_time_travel(char *str)
{ {
if (strcmp(str, "=inf-cpu") == 0) { if (strcmp(str, "=inf-cpu") == 0) {
time_travel_mode = TT_MODE_INFCPU; time_travel_mode = TT_MODE_INFCPU;
...@@ -862,7 +863,7 @@ __uml_help(setup_time_travel, ...@@ -862,7 +863,7 @@ __uml_help(setup_time_travel,
"devices using it, assuming the device has the right capabilities.\n" "devices using it, assuming the device has the right capabilities.\n"
"The optional ID is a 64-bit integer that's sent to the central scheduler.\n"); "The optional ID is a 64-bit integer that's sent to the central scheduler.\n");
int setup_time_travel_start(char *str) static int setup_time_travel_start(char *str)
{ {
int err; int err;
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/sched/signal.h> #include <linux/sched/signal.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/mmu_context.h>
#include <as-layout.h> #include <as-layout.h>
#include <mem_user.h> #include <mem_user.h>
#include <os.h> #include <os.h>
...@@ -576,12 +577,6 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, ...@@ -576,12 +577,6 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
} }
EXPORT_SYMBOL(flush_tlb_range); EXPORT_SYMBOL(flush_tlb_range);
void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
unsigned long end)
{
fix_range(mm, start, end, 0);
}
void flush_tlb_mm(struct mm_struct *mm) void flush_tlb_mm(struct mm_struct *mm)
{ {
struct vm_area_struct *vma; struct vm_area_struct *vma;
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <asm/cpufeature.h> #include <asm/cpufeature.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/text-patching.h>
#include <as-layout.h> #include <as-layout.h>
#include <arch.h> #include <arch.h>
#include <init.h> #include <init.h>
......
...@@ -11,4 +11,6 @@ extern void __init uml_dtb_init(void); ...@@ -11,4 +11,6 @@ extern void __init uml_dtb_init(void);
static inline void uml_dtb_init(void) { } static inline void uml_dtb_init(void) { }
#endif #endif
extern int __init read_initrd(void);
#endif #endif
...@@ -63,7 +63,7 @@ const struct net_kern_info ethertap_kern_info = { ...@@ -63,7 +63,7 @@ const struct net_kern_info ethertap_kern_info = {
.write = etap_write, .write = etap_write,
}; };
int ethertap_setup(char *str, char **mac_out, void *data) static int ethertap_setup(char *str, char **mac_out, void *data)
{ {
struct ethertap_init *init = data; struct ethertap_init *init = data;
......
...@@ -53,7 +53,7 @@ const struct net_kern_info tuntap_kern_info = { ...@@ -53,7 +53,7 @@ const struct net_kern_info tuntap_kern_info = {
.write = tuntap_write, .write = tuntap_write,
}; };
int tuntap_setup(char *str, char **mac_out, void *data) static int tuntap_setup(char *str, char **mac_out, void *data)
{ {
struct tuntap_init *init = data; struct tuntap_init *init = data;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <init.h> #include <init.h>
#include <elf_user.h> #include <elf_user.h>
#include <mem_user.h> #include <mem_user.h>
#include "internal.h"
typedef Elf32_auxv_t elf_auxv_t; typedef Elf32_auxv_t elf_auxv_t;
......
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __UM_OS_LINUX_INTERNAL_H
#define __UM_OS_LINUX_INTERNAL_H
/*
* elf_aux.c
*/
void scan_elf_aux(char **envp);
/*
* mem.c
*/
void check_tmpexec(void);
/*
* skas/process.c
*/
void wait_stub_done(int pid);
#endif /* __UM_OS_LINUX_INTERNAL_H */
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <kern_util.h> #include <kern_util.h>
#include <os.h> #include <os.h>
#include <um_malloc.h> #include <um_malloc.h>
#include "internal.h"
#define PGD_BOUND (4 * 1024 * 1024) #define PGD_BOUND (4 * 1024 * 1024)
#define STACKSIZE (8 * 1024 * 1024) #define STACKSIZE (8 * 1024 * 1024)
...@@ -102,8 +103,6 @@ static void setup_env_path(void) ...@@ -102,8 +103,6 @@ static void setup_env_path(void)
} }
} }
extern void scan_elf_aux( char **envp);
int __init main(int argc, char **argv, char **envp) int __init main(int argc, char **argv, char **envp)
{ {
char **new_argv; char **new_argv;
...@@ -184,6 +183,11 @@ int __init main(int argc, char **argv, char **envp) ...@@ -184,6 +183,11 @@ int __init main(int argc, char **argv, char **envp)
extern void *__real_malloc(int); extern void *__real_malloc(int);
/* workaround for -Wmissing-prototypes warnings */
void *__wrap_malloc(int size);
void *__wrap_calloc(int n, int size);
void __wrap_free(void *ptr);
void *__wrap_malloc(int size) void *__wrap_malloc(int size)
{ {
void *ret; void *ret;
......
...@@ -15,7 +15,9 @@ ...@@ -15,7 +15,9 @@
#include <sys/vfs.h> #include <sys/vfs.h>
#include <linux/magic.h> #include <linux/magic.h>
#include <init.h> #include <init.h>
#include <kern_util.h>
#include <os.h> #include <os.h>
#include "internal.h"
/* /*
* kasan_map_memory - maps memory from @start with a size of @len. * kasan_map_memory - maps memory from @start with a size of @len.
......
...@@ -72,7 +72,7 @@ static int signals_blocked; ...@@ -72,7 +72,7 @@ static int signals_blocked;
static unsigned int signals_pending; static unsigned int signals_pending;
static unsigned int signals_active = 0; static unsigned int signals_active = 0;
void sig_handler(int sig, struct siginfo *si, mcontext_t *mc) static void sig_handler(int sig, struct siginfo *si, mcontext_t *mc)
{ {
int enabled = signals_enabled; int enabled = signals_enabled;
...@@ -108,7 +108,7 @@ static void timer_real_alarm_handler(mcontext_t *mc) ...@@ -108,7 +108,7 @@ static void timer_real_alarm_handler(mcontext_t *mc)
timer_handler(SIGALRM, NULL, &regs); timer_handler(SIGALRM, NULL, &regs);
} }
void timer_alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) static void timer_alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc)
{ {
int enabled; int enabled;
......
...@@ -17,11 +17,10 @@ ...@@ -17,11 +17,10 @@
#include <skas.h> #include <skas.h>
#include <sysdep/ptrace.h> #include <sysdep/ptrace.h>
#include <sysdep/stub.h> #include <sysdep/stub.h>
#include "../internal.h"
extern char batch_syscall_stub[], __syscall_stub_start[]; extern char batch_syscall_stub[], __syscall_stub_start[];
extern void wait_stub_done(int pid);
static inline unsigned long *check_init_stack(struct mm_id * mm_idp, static inline unsigned long *check_init_stack(struct mm_id * mm_idp,
unsigned long *stack) unsigned long *stack)
{ {
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <skas.h> #include <skas.h>
#include <sysdep/stub.h> #include <sysdep/stub.h>
#include <linux/threads.h> #include <linux/threads.h>
#include "../internal.h"
int is_skas_winch(int pid, int fd, void *data) int is_skas_winch(int pid, int fd, void *data)
{ {
......
...@@ -20,10 +20,12 @@ ...@@ -20,10 +20,12 @@
#include <asm/unistd.h> #include <asm/unistd.h>
#include <init.h> #include <init.h>
#include <os.h> #include <os.h>
#include <kern_util.h>
#include <mem_user.h> #include <mem_user.h>
#include <ptrace_user.h> #include <ptrace_user.h>
#include <registers.h> #include <registers.h>
#include <skas.h> #include <skas.h>
#include "internal.h"
static void ptrace_child(void) static void ptrace_child(void)
{ {
...@@ -221,8 +223,6 @@ static void __init check_ptrace(void) ...@@ -221,8 +223,6 @@ static void __init check_ptrace(void)
check_sysemu(); check_sysemu();
} }
extern void check_tmpexec(void);
static void __init check_coredump_limit(void) static void __init check_coredump_limit(void)
{ {
struct rlimit lim; struct rlimit lim;
......
...@@ -54,6 +54,8 @@ extern int ptrace_get_thread_area(struct task_struct *child, int idx, ...@@ -54,6 +54,8 @@ extern int ptrace_get_thread_area(struct task_struct *child, int idx,
extern int ptrace_set_thread_area(struct task_struct *child, int idx, extern int ptrace_set_thread_area(struct task_struct *child, int idx,
struct user_desc __user *user_desc); struct user_desc __user *user_desc);
extern int arch_switch_tls(struct task_struct *to);
#else #else
#define PT_REGS_R8(r) UPT_R8(&(r)->regs) #define PT_REGS_R8(r) UPT_R8(&(r)->regs)
...@@ -83,5 +85,9 @@ extern long arch_prctl(struct task_struct *task, int option, ...@@ -83,5 +85,9 @@ extern long arch_prctl(struct task_struct *task, int option,
unsigned long __user *addr); unsigned long __user *addr);
#endif #endif
#define user_stack_pointer(regs) PT_REGS_SP(regs) #define user_stack_pointer(regs) PT_REGS_SP(regs)
extern void arch_switch_to(struct task_struct *to);
#endif /* __UM_X86_PTRACE_H */ #endif /* __UM_X86_PTRACE_H */
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
* Licensed under the GPL * Licensed under the GPL
*/ */
#include <arch.h>
#include <signal.h> #include <signal.h>
#include <kern_util.h> #include <kern_util.h>
#include <longjmp.h> #include <longjmp.h>
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* Licensed under the GPL * Licensed under the GPL
*/ */
#include <arch.h>
#include <sysdep/ptrace.h> #include <sysdep/ptrace.h>
void arch_check_bugs(void) void arch_check_bugs(void)
......
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
#include <linux/elf.h> #include <linux/elf.h>
#include <linux/elfcore.h>
#include <linux/coredump.h> #include <linux/coredump.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/mm.h> #include <linux/mm.h>
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
* Licensed under the GPL * Licensed under the GPL
*/ */
#include <arch.h>
#include <sysdep/ptrace.h> #include <sysdep/ptrace.h>
/* These two are from asm-um/uaccess.h and linux/module.h, check them. */ /* These two are from asm-um/uaccess.h and linux/module.h, check them. */
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#define __FRAME_OFFSETS #define __FRAME_OFFSETS
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <sysdep/ptrace.h> #include <sysdep/ptrace.h>
#include <sysdep/mcontext.h>
void get_regs_from_mc(struct uml_pt_regs *regs, mcontext_t *mc) void get_regs_from_mc(struct uml_pt_regs *regs, mcontext_t *mc)
{ {
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#include <linux/elf.h> #include <linux/elf.h>
#include <registers.h> #include <registers.h>
int have_xstate_support; static int have_xstate_support;
int save_i387_registers(int pid, unsigned long *fp_regs) int save_i387_registers(int pid, unsigned long *fp_regs)
{ {
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <sys/syscall.h> #include <sys/syscall.h>
#include <unistd.h> #include <unistd.h>
#include <os.h>
#include <sysdep/tls.h> #include <sysdep/tls.h>
#ifndef PTRACE_GET_THREAD_AREA #ifndef PTRACE_GET_THREAD_AREA
......
...@@ -10,8 +10,6 @@ ...@@ -10,8 +10,6 @@
#include <registers.h> #include <registers.h>
#include <skas.h> #include <skas.h>
extern int arch_switch_tls(struct task_struct *to);
void arch_switch_to(struct task_struct *to) void arch_switch_to(struct task_struct *to)
{ {
int err = arch_switch_tls(to); int err = arch_switch_tls(to);
......
/* SPDX-License-Identifier: GPL-2.0 */ /* SPDX-License-Identifier: GPL-2.0 */
#ifndef __X86_UM_SYSDEP_ARCHSETJMP_H
#define __X86_UM_SYSDEP_ARCHSETJMP_H
#ifdef __i386__ #ifdef __i386__
#include "archsetjmp_32.h" #include "archsetjmp_32.h"
#else #else
#include "archsetjmp_64.h" #include "archsetjmp_64.h"
#endif #endif
unsigned long get_thread_reg(int reg, jmp_buf *buf);
#endif /* __X86_UM_SYSDEP_ARCHSETJMP_H */
...@@ -6,6 +6,9 @@ ...@@ -6,6 +6,9 @@
#include <linux/kbuild.h> #include <linux/kbuild.h>
#include <asm/mman.h> #include <asm/mman.h>
/* workaround for a warning with -Wmissing-prototypes */
void foo(void);
void foo(void) void foo(void)
{ {
#include <common-offsets.h> #include <common-offsets.h>
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/personality.h> #include <linux/personality.h>
#include <linux/ptrace.h> #include <linux/ptrace.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/syscalls.h>
#include <asm/unistd.h> #include <asm/unistd.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <asm/ucontext.h> #include <asm/ucontext.h>
...@@ -155,7 +156,7 @@ static int copy_sc_from_user(struct pt_regs *regs, ...@@ -155,7 +156,7 @@ static int copy_sc_from_user(struct pt_regs *regs,
struct sigcontext __user *from) struct sigcontext __user *from)
{ {
struct sigcontext sc; struct sigcontext sc;
int err, pid; int err;
/* Always make any pending restarted system calls return -EINTR */ /* Always make any pending restarted system calls return -EINTR */
current->restart_block.fn = do_no_restart_syscall; current->restart_block.fn = do_no_restart_syscall;
...@@ -201,10 +202,10 @@ static int copy_sc_from_user(struct pt_regs *regs, ...@@ -201,10 +202,10 @@ static int copy_sc_from_user(struct pt_regs *regs,
#undef GETREG #undef GETREG
pid = userspace_pid[current_thread_info()->cpu];
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
if (have_fpx_regs) { if (have_fpx_regs) {
struct user_fxsr_struct fpx; struct user_fxsr_struct fpx;
int pid = userspace_pid[current_thread_info()->cpu];
err = copy_from_user(&fpx, err = copy_from_user(&fpx,
&((struct _fpstate __user *)sc.fpstate)->_fxsr_env[0], &((struct _fpstate __user *)sc.fpstate)->_fxsr_env[0],
...@@ -240,7 +241,7 @@ static int copy_sc_to_user(struct sigcontext __user *to, ...@@ -240,7 +241,7 @@ static int copy_sc_to_user(struct sigcontext __user *to,
{ {
struct sigcontext sc; struct sigcontext sc;
struct faultinfo * fi = &current->thread.arch.faultinfo; struct faultinfo * fi = &current->thread.arch.faultinfo;
int err, pid; int err;
memset(&sc, 0, sizeof(struct sigcontext)); memset(&sc, 0, sizeof(struct sigcontext));
#define PUTREG(regno, regname) sc.regname = regs->regs.gp[HOST_##regno] #define PUTREG(regno, regname) sc.regname = regs->regs.gp[HOST_##regno]
...@@ -288,10 +289,9 @@ static int copy_sc_to_user(struct sigcontext __user *to, ...@@ -288,10 +289,9 @@ static int copy_sc_to_user(struct sigcontext __user *to,
if (err) if (err)
return 1; return 1;
pid = userspace_pid[current_thread_info()->cpu];
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
if (have_fpx_regs) { if (have_fpx_regs) {
int pid = userspace_pid[current_thread_info()->cpu];
struct user_fxsr_struct fpx; struct user_fxsr_struct fpx;
err = save_fpx_registers(pid, (unsigned long *) &fpx); err = save_fpx_registers(pid, (unsigned long *) &fpx);
...@@ -450,7 +450,7 @@ int setup_signal_stack_si(unsigned long stack_top, struct ksignal *ksig, ...@@ -450,7 +450,7 @@ int setup_signal_stack_si(unsigned long stack_top, struct ksignal *ksig,
return 0; return 0;
} }
long sys_sigreturn(void) SYSCALL_DEFINE0(sigreturn)
{ {
unsigned long sp = PT_REGS_SP(&current->thread.regs); unsigned long sp = PT_REGS_SP(&current->thread.regs);
struct sigframe __user *frame = (struct sigframe __user *)(sp - 8); struct sigframe __user *frame = (struct sigframe __user *)(sp - 8);
...@@ -557,7 +557,7 @@ int setup_signal_stack_si(unsigned long stack_top, struct ksignal *ksig, ...@@ -557,7 +557,7 @@ int setup_signal_stack_si(unsigned long stack_top, struct ksignal *ksig,
} }
#endif #endif
long sys_rt_sigreturn(void) SYSCALL_DEFINE0(rt_sigreturn)
{ {
unsigned long sp = PT_REGS_SP(&current->thread.regs); unsigned long sp = PT_REGS_SP(&current->thread.regs);
struct rt_sigframe __user *frame = struct rt_sigframe __user *frame =
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
static int host_supports_tls = -1; static int host_supports_tls = -1;
int host_gdt_entry_tls_min; int host_gdt_entry_tls_min;
int do_set_thread_area(struct user_desc *info) static int do_set_thread_area(struct user_desc *info)
{ {
int ret; int ret;
u32 cpu; u32 cpu;
...@@ -36,22 +36,6 @@ int do_set_thread_area(struct user_desc *info) ...@@ -36,22 +36,6 @@ int do_set_thread_area(struct user_desc *info)
return ret; return ret;
} }
int do_get_thread_area(struct user_desc *info)
{
int ret;
u32 cpu;
cpu = get_cpu();
ret = os_get_thread_area(info, userspace_pid[cpu]);
put_cpu();
if (ret)
printk(KERN_ERR "PTRACE_GET_THREAD_AREA failed, err = %d, "
"index = %d\n", ret, info->entry_number);
return ret;
}
/* /*
* sys_get_thread_area: get a yet unused TLS descriptor index. * sys_get_thread_area: get a yet unused TLS descriptor index.
* XXX: Consider leaving one free slot for glibc usage at first place. This must * XXX: Consider leaving one free slot for glibc usage at first place. This must
...@@ -231,7 +215,6 @@ int arch_set_tls(struct task_struct *new, unsigned long tls) ...@@ -231,7 +215,6 @@ int arch_set_tls(struct task_struct *new, unsigned long tls)
return ret; return ret;
} }
/* XXX: use do_get_thread_area to read the host value? I'm not at all sure! */
static int get_tls_entry(struct task_struct *task, struct user_desc *info, static int get_tls_entry(struct task_struct *task, struct user_desc *info,
int idx) int idx)
{ {
......
...@@ -14,6 +14,9 @@ ...@@ -14,6 +14,9 @@
COMMENT(#val " / sizeof(unsigned long)"); \ COMMENT(#val " / sizeof(unsigned long)"); \
DEFINE(sym, val / sizeof(unsigned long)) DEFINE(sym, val / sizeof(unsigned long))
/* workaround for a warning with -Wmissing-prototypes */
void foo(void);
void foo(void) void foo(void)
{ {
#ifdef __i386__ #ifdef __i386__
......
...@@ -13,6 +13,12 @@ ...@@ -13,6 +13,12 @@
#include <linux/getcpu.h> #include <linux/getcpu.h>
#include <asm/unistd.h> #include <asm/unistd.h>
/* workaround for -Wmissing-prototypes warnings */
int __vdso_clock_gettime(clockid_t clock, struct __kernel_old_timespec *ts);
int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz);
__kernel_old_time_t __vdso_time(__kernel_old_time_t *t);
long __vdso_getcpu(unsigned int *cpu, unsigned int *node, struct getcpu_cache *unused);
int __vdso_clock_gettime(clockid_t clock, struct __kernel_old_timespec *ts) int __vdso_clock_gettime(clockid_t clock, struct __kernel_old_timespec *ts)
{ {
long ret; long ret;
...@@ -54,7 +60,7 @@ __kernel_old_time_t __vdso_time(__kernel_old_time_t *t) ...@@ -54,7 +60,7 @@ __kernel_old_time_t __vdso_time(__kernel_old_time_t *t)
__kernel_old_time_t time(__kernel_old_time_t *t) __attribute__((weak, alias("__vdso_time"))); __kernel_old_time_t time(__kernel_old_time_t *t) __attribute__((weak, alias("__vdso_time")));
long long
__vdso_getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *unused) __vdso_getcpu(unsigned int *cpu, unsigned int *node, struct getcpu_cache *unused)
{ {
/* /*
* UML does not support SMP, we can cheat here. :) * UML does not support SMP, we can cheat here. :)
...@@ -68,5 +74,5 @@ __vdso_getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *unused) ...@@ -68,5 +74,5 @@ __vdso_getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *unused)
return 0; return 0;
} }
long getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache) long getcpu(unsigned int *cpu, unsigned int *node, struct getcpu_cache *tcache)
__attribute__((weak, alias("__vdso_getcpu"))); __attribute__((weak, alias("__vdso_getcpu")));
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment