It's better not to ask multiple questions at once as not everyone can or will answer everything. Still, I'll give a short answer to each.
Does the Linux kernel internally operate with virtual or physical addresses? What especially confuses me is that there are several types of addresses (logical, virtual, bus and physical) and they are all valid and operable by the kernel.
Yes. Different parts of the kernel use different address spaces.
While kernel code is processing a system call, its memory mappings include both the whole kernel memory space and the whole memory space of the process (unless your kernel has high memory configured in, but that's too complicated to go into here). These are all logical (a.k.a. virtual) addresses: the high-order bits of the address indicate which page to look up in the MMU, and the low-order bits are a linear address inside the page. The memory mappings inside the MMU change whenever a task switch occurs (changing the page table in the MMU is a big part of a task switch).
Some device drivers need to manipulate memory addresses that are valid for the device they are driving. These are often physical addresses, although some architectures have an IOMMU so that devices also see logical addresses of their own. Of course, the memory management subsystem in the kernel needs to manipulate lots of different kinds of addresses.
Is that correct that CPU instructions can't directly address data stored in peripheral devices and therefore addressable memory is used, i.e. buffers, for these purposes?
This is architecture-dependent. Most architectures do have some kind of DMA (direct memory access), that allows at least some communication with devices to be done via RAM. Additionally, on some architectures (e.g. ARM) all device accesses are done with load and store instructions at appropriate addresses, while others (e.g. i386) have specific processor instructions for that purpose. See Memory-mapped I/O for more details.
Can a process sleep when requesting a semaphore (which has a value 0) and has to wait for it?
Yes, taking a semaphore (
down and friends) is a blocking operation. This is well-explained in the book.
Atomic operations -- are these guaranteed by specific CPU instructions?
Yes. The details are very architecture-specific. All platforms intended for multitasking provide at least one atomic primitive for synchronization such as compare-and-swap, test-and-set, load-link+store-conditional, etc. In addition to using the correct primitive, the code may need to take care to use proper memory barriers on multiprocessor systems. The Linux kernel provides an implementation of its synchronization primitives for each architecture it supports, so that you in turn only need to use the kernel's portable primitives.